diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 0000000000..46e2d25b8c --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,17 @@ +# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json +language: "en-US" +early_access: false +reviews: + profile: "chill" + request_changes_workflow: true + high_level_summary: true + poem: true + review_status: true + collapse_walkthrough: false + auto_review: + enabled: true + drafts: false + base_branches: + - develop +chat: + auto_reply: true \ No newline at end of file diff --git a/.env.example b/.env.example new file mode 100644 index 0000000000..399d5e6aab --- /dev/null +++ b/.env.example @@ -0,0 +1,31 @@ +# 👋 Welcome, we're glad you're setting up an installation of Talawa-admin. Copy this +# file to .env or set the variables in your local environment manually. + + +# Custom port number for the talawa-admin development server to run on. Default is 4321. + +PORT=4321 + +# Run Talawa-api locally in your system, and put its url into the same. + +REACT_APP_TALAWA_URL= + +# Do you want to setup and use "I'm not a robot" Checkbox (Google Recaptcha)? +# If no, leave blank, else write yes +# Example: REACT_APP_USE_RECAPTCHA=yes + +REACT_APP_USE_RECAPTCHA= + +# If you are using Google Recaptcha, i.e., REACT_APP_USE_RECAPTCHA=yes, read the following steps +# Get the google recaptcha site key from google recaptcha admin or https://www.google.com/recaptcha/admin/create +# from here for reCAPTCHA v2 and "I'm not a robot" Checkbox, and paste the key here. +# Note: In domains, fill localhost + +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 + +# 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 diff --git a/.eslintignore b/.eslintignore index e69de29bb2..7e45de312a 100644 --- a/.eslintignore +++ b/.eslintignore @@ -0,0 +1,2 @@ +# 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 diff --git a/.eslintrc.json b/.eslintrc.json index a1f8002a3c..ee118a5a58 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,6 +1,7 @@ { "env": { "browser": true, + "node": true, "es6": true }, @@ -10,7 +11,9 @@ "eslint:recommended", "plugin:jest/recommended", "plugin:prettier/recommended", - "plugin:@typescript-eslint/recommended" + "plugin:@typescript-eslint/recommended", + "eslint-config-prettier", + "prettier" ], "globals": { "Atomics": "readonly", @@ -26,12 +29,95 @@ }, // Specify the ESLint plugins tobe used - "plugins": ["react", "@typescript-eslint", "react-hooks", "jest"], + "plugins": [ + "react", + "@typescript-eslint", + "jest", + "import", + "eslint-plugin-tsdoc", + "prettier" + ], "rules": { - "react/destructuring-assignment": ["warn", "always"], - "react/no-multi-comp": ["error", { "ignoreStateless": false }], - "react/jsx-filename-extension": ["error", { "extensions": [".tsx"] }], + "react/destructuring-assignment": "error", + "@typescript-eslint/explicit-module-boundary-types": "error", + "react/no-multi-comp": [ + "error", + { + "ignoreStateless": false + } + ], + "react/jsx-filename-extension": [ + "error", + { + "extensions": [".tsx"] + } + ], + "import/no-duplicates": "error", + "tsdoc/syntax": "error", + "@typescript-eslint/ban-ts-comment": "error", + "@typescript-eslint/no-explicit-any": "error", + "@typescript-eslint/no-inferrable-types": "error", + "@typescript-eslint/no-non-null-asserted-optional-chain": "error", + "@typescript-eslint/no-non-null-assertion": "error", + "@typescript-eslint/no-var-requires": "error", + "@typescript-eslint/ban-types": "error", + "@typescript-eslint/no-duplicate-enum-values": "error", + "@typescript-eslint/array-type": "error", + "@typescript-eslint/consistent-type-assertions": "error", + "@typescript-eslint/consistent-type-imports": "error", + "@typescript-eslint/explicit-function-return-type": [ + 2, + { + "allowExpressions": true, + "allowTypedFunctionExpressions": true + } + ], + "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"] + }, + { + "selector": "typeParameter", + "format": ["PascalCase"], + "prefix": ["T"] + }, + { + "selector": "variable", + "format": ["camelCase", "UPPER_CASE", "PascalCase"], + "leadingUnderscore": "allow" + }, + { + "selector": "parameter", + "format": ["camelCase"], + "leadingUnderscore": "allow" + }, + { + "selector": "function", + "format": ["camelCase", "PascalCase"] + }, + { + "selector": "memberLike", + "modifiers": ["private"], + "format": ["camelCase"], + "leadingUnderscore": "require" + }, + { + "selector": "variable", + "modifiers": ["exported"], + "format": null + } + ], // Ensures that components are always written in PascalCase "react/jsx-pascal-case": [ "error", @@ -42,23 +128,16 @@ "react/jsx-equals-spacing": ["warn", "never"], "react/no-this-in-sfc": "error", - // Ensures that components are always indented by 2 spaces - "react/jsx-indent": ["warn", 2], - "react/jsx-tag-spacing": [ - "warn", - { - "afterOpening": "never", - "beforeClosing": "never", - "beforeSelfClosing": "always" - } - ], + // 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": [ - "error", + 0, { "namedComponents": "function-declaration" } - ] + ], + "prettier/prettier": "error" }, // Let ESLint use the react version in the package.json diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug-report.md similarity index 60% rename from .github/ISSUE_TEMPLATE/bug_report.md rename to .github/ISSUE_TEMPLATE/bug-report.md index ccbb9c4d8e..493322305f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -1,9 +1,10 @@ --- -name: Bug report +name: Bug Report about: Create a report to help us improve. -title: Bug report -labels: Bug -assignees: "" +title: Bug Report +labels: bug +assignees: '' + --- **Describe the bug** @@ -27,3 +28,7 @@ A clear and concise description of how the code performed w.r.t expectations. If applicable, add screenshots to help explain your problem. **Additional details** +Add any other context or screenshots about the feature request here. + +**Potential internship candidates** +Please read this if you are planning to apply for a Palisadoes Foundation internship https://github.com/PalisadoesFoundation/talawa/issues/359 diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature-request.md similarity index 69% rename from .github/ISSUE_TEMPLATE/feature_request.md rename to .github/ISSUE_TEMPLATE/feature-request.md index 1c93611c44..60d6401dcf 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -1,9 +1,10 @@ --- -name: Feature request +name: Feature Request about: Suggest an idea for this project -title: Feature request -labels: Feature -assignees: "" +title: Feature Request +labels: feature request +assignees: '' + --- **Is your feature request related to a problem? Please describe.** @@ -20,3 +21,6 @@ A clear and concise description of approach to be followed. **Additional context** Add any other context or screenshots about the feature request here. + +**Potential internship candidates** +Please read this if you are planning to apply for a Palisadoes Foundation internship https://github.com/PalisadoesFoundation/talawa/issues/359 diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml new file mode 100644 index 0000000000..2fc49726ff --- /dev/null +++ b/.github/dependabot.yaml @@ -0,0 +1,18 @@ +# Configuration for automated dependency updates using Dependabot +version: 2 +updates: + # Define the target package ecosystem + - package-ecosystem: "npm" + # Specify the root directory + directory: "/" + # Schedule automated updates to run weekly + schedule: + interval: "weekly" + # Labels to apply to Dependabot PRs + labels: + - "dependencies" + # Specify the target branch for PRs + target-branch: "develop" + # Customize commit message prefix + commit-message: + prefix: "chore(deps):" \ No newline at end of file diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index b3f679554c..9e3081d0ee 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,13 +1,40 @@ - + + + **What kind of change does this PR introduce?** +**Issue Number:** + +Fixes # + **Did you add tests for your changes?** + + +**Snapshots/Videos:** + + + **If relevant, did you update the documentation?** + + **Summary** @@ -18,3 +45,9 @@ **Other information** + + + +**Have you read the [contributing guide](https://github.com/PalisadoesFoundation/talawa-admin/blob/master/CONTRIBUTING.md)?** + + diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000000..1e9a81eaf8 --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,47 @@ +# Talawa GitHub Workflows Guidelines + +Follow these guidelines when contributing to this directory. + +## General + +Any changes to files in this directory are flagged when pull requests are run. Make changes only on the advice of a contributor. + +## YAML Workflow Files + +The YAML files in this directory have very specific roles depending on the type of workflow. + +Whenever possible you must ensure that: +1. The file roles below are maintained +1. The sequence of the jobs in the workflows are maintained using [GitHub Action dependencies](https://docs.github.com/en/actions/learn-github-actions/managing-complex-workflows). + +### File Roles +Follow these guidelines when creating new YAML defined GitHub actions. This is done to make troubleshooting easier. + +1. `Issue` Workflows: + 1. Place all actions related to issues in the `issues.yml` file. +1. `Pull Request` workflows to be run by: + 1. Workflows to run **First Time** repo contributors: + 1. Place all actions related to to this in the `pull-request-target.yml` file. + 1. Workflows to be run by **ALL** repo contributors: + 1. Place all actions related to pull requests in the `pull-request.yml` file. +1. `Push` workflows: + 1. Place all actions related to pushes in the `push.yml` file. + +#### File Role Exceptions + +There are some exceptions to these rules in which jobs can be placed in dedicated separate files: +1. Jobs that require unique `cron:` schedules +1. Jobs that require unique `paths:` statements that operate only when files in a specific path are updated. +1. Jobs only work correctly if they have a dedicated file (eg. `CodeQL`) + +## Scripts + +Follow these guidelines when creating or modifying scripts in this directory. + +1. All scripts in this directory must be written in python3 for consistency. +1. The python3 scripts must follow the following coding standards. Run these commands against your scripts before submitting PRs that modify or create python3 scripts in this directory. + 1. Pycodestyle + 1. Pydocstyle + 1. Pylint + 1. Flake8 +1. All scripts must run a main() function. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 3efc4fd51f..0000000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: Continuous Integration -on: [pull_request] -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Install Dependencies - run: yarn - - name: Run tests - run: yarn test - - \ No newline at end of file diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index ccd6fc3705..0000000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,67 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -on: - push: - branches: [ master ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ master ] - schedule: - - cron: '22 0 * * 5' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - language: [ 'javascript' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] - # Learn more: - # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/codeql-codescan.yml b/.github/workflows/codeql-codescan.yml new file mode 100644 index 0000000000..e9eb5c5d49 --- /dev/null +++ b/.github/workflows/codeql-codescan.yml @@ -0,0 +1,43 @@ +############################################################################## +############################################################################## +# +# NOTE! +# +# Please read the README.md file in this directory that defines what should +# be placed in this file +# +############################################################################## +############################################################################## + +name: codeql codescan workflow + +on: + pull_request: + branches: + - '**' + push: + branches: + - '**' +jobs: + CodeQL: + name: Analyse code with codeQL on push + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + language: [ 'javascript' ] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + debug: true + + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/compare_translations.py b/.github/workflows/compare_translations.py new file mode 100644 index 0000000000..fd4f772605 --- /dev/null +++ b/.github/workflows/compare_translations.py @@ -0,0 +1,186 @@ +"""Script to encourage more efficient coding practices. +Methodology: + + Utility for comparing translations between default and other languages. + + This module defines a function to compare two translations + and print any missing keys in the other language's translation. +Attributes: + + FileTranslation : Named tuple to represent a combination + of file and missing translations. + + Fields: + - file (str): The file name. + - missing_translations (list): List of missing translations. + +Functions: + compare_translations(default_translation, other_translation): + Compare two translations and print missing keys. + + load_translation(filepath): + Load translation from a file. + + check_translations(): + Load the default translation and compare it with other translations. + + main(): + The main function to run the script. + Parses command-line arguments, checks for the + existence of the specified directory, and then + calls check_translations with the provided or default directory. + + +Usage: + This script can be executed to check and print missing + translations in other languages based on the default English translation. + +Example: + python compare_translations.py +NOTE: + This script complies with our python3 coding and documentation standards + and should be used as a reference guide. It complies with: + + 1) Pylint + 2) Pydocstyle + 3) Pycodestyle + 4) Flake8 + +""" +# standard imports +import argparse +import json +import os +import sys +from collections import namedtuple + +# Named tuple for file and missing +# translations combination +FileTranslation = namedtuple("FileTranslation", + ["file", "missing_translations"]) + + +def compare_translations(default_translation, + other_translation, default_file, other_file): + """Compare two translations and return detailed info about missing/mismatched keys. + + Args: + default_translation (dict): The default translation (en.json). + other_translation (dict): The other language translation. + default_file (str): The name of the default translation file. + other_file (str): The name of the other + translation file. + + Returns: + list: A list of detailed error messages for each missing/mismatched key. + """ + errors = [] + + # Check for missing keys in other_translation + for key in default_translation: + if key not in other_translation: + error_msg = f"Missing Key: '{key}' - This key from '{default_file}' is missing in '{other_file}'." + errors.append(error_msg) + # Check for keys in other_translation that don't match any in default_translation + for key in other_translation: + if key not in default_translation: + error_msg = f"Error Key: '{key}' - This key in '{other_file}' does not match any key in '{default_file}'." + errors.append(error_msg) + return errors + + +def load_translation(filepath): + """Load translation from a file. + + Args: + filepath: Path to the translation file + + Returns: + translation: Loaded translation + """ + try: + with open(filepath, "r", encoding="utf-8") as file: + content = file.read() + if not content.strip(): + raise ValueError(f"File {filepath} is empty.") + translation = json.loads(content) + return translation + except json.JSONDecodeError as e: + raise ValueError(f"Error decoding JSON from file {filepath}: {e}") + + +def check_translations(directory): + """Load default translation and compare with other translations. + + Args: + directory (str): The directory containing translation files. + + Returns: + None + """ + default_language_dir = os.path.join(directory, "en") + default_files = ["common.json", "errors.json", "translation.json"] + default_translations = {} + for file in default_files: + file_path = os.path.join(default_language_dir, file) + default_translations[file] = load_translation(file_path) + + languages = os.listdir(directory) + languages.remove("en") # Exclude default language directory + + + error_found = False + + for language in languages: + language_dir = os.path.join(directory, language) + for file in default_files: + default_translation = default_translations[file] + other_file_path = os.path.join(language_dir, file) + other_translation = load_translation(other_file_path) + + # Compare translations and get detailed error messages + errors = compare_translations( + default_translation, other_translation, f"en/{file}", f"{language}/{file}" + ) + if errors: + error_found = True + print(f"File {language}/{file} has missing translations for:") + for error in errors: + print(f" - {error}") + + + if error_found: + sys.exit(1) # Exit with an error status code + else: + print("All translations are present") + sys.exit(0) + + +def main(): + """ + + Parse command-line arguments, check for the existence of the specified directory + and call check_translations with the provided or default directory. + + """ + parser = argparse.ArgumentParser( + description="Check and print missing translations for all non-default languages." + ) + parser.add_argument( + "--directory", + type=str, + nargs="?", + default=os.path.join(os.getcwd(), "locales"), + help="Directory containing translation files(relative to the root directory).", + ) + args = parser.parse_args() + + if not os.path.exists(args.directory): + print(f"Error: The specified directory '{args.directory}' does not exist.") + sys.exit(1) + + check_translations(args.directory) + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/countline.py b/.github/workflows/countline.py new file mode 100755 index 0000000000..d0b03c503f --- /dev/null +++ b/.github/workflows/countline.py @@ -0,0 +1,297 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +"""Script to encourage more efficient coding practices. + +Methodology: + + Analyses the `lib` and `test` directories to find files that exceed a + pre-defined number of lines of code. + + This script was created to help improve code quality by encouraging + contributors to create reusable code. + +NOTE: + + This script complies with our python3 coding and documentation standards + and should be used as a reference guide. It complies with: + + 1) Pylint + 2) Pydocstyle + 3) Pycodestyle + 4) Flake8 + + Run these commands from the CLI to ensure the code is compliant for all + your pull requests. + +""" + +# Standard imports +import os +import sys +import argparse +from collections import namedtuple + + +def _valid_filename(filepath): + """Determine whether filepath has the correct filename. + + Args: + filepath: Filepath to check + + Returns: + result: True if valid + + """ + # Initialize key variables + invalid_filenames = [".test.", ".spec."] + result = True + + # Test + for invalid_filename in invalid_filenames: + if invalid_filename.lower() not in filepath.lower(): + continue + result = False + + return result + + +def _valid_extension(filepath): + """Determine whether filepath has the correct extension. + + Args: + filepath: Filepath to check + + Returns: + result: True if valid + + """ + # Initialize key variables + invalid_extensions = [".css", ".jpg", ".png", ".jpeg"] + result = True + + # Test + for invalid_extension in invalid_extensions: + if filepath.lower().endswith(invalid_extension.lower()) is False: + continue + result = False + + return result + + +def _valid_exclusions(excludes): + """Create a list of full file paths to exclude from the analysis. + + Args: + excludes: Excludes object + + Returns: + result: A list of full file paths + + """ + # Initialize key variables + result = [] + filenames = [] + more_filenames = [] + + # Create a list of files to ignore + if bool(excludes.files): + filenames = excludes.files + if bool(excludes.directories): + more_filenames = _filepaths_in_directories(excludes.directories) + filenames.extend(more_filenames) + + # Remove duplicates + filenames = list(set(filenames)) + + # Process files + for filename in filenames: + # Ignore files that appear to be full paths because they start + # with a '/' or whatever the OS uses to distinguish directories + if filename.startswith(os.sep): + continue + + # Create a file path + filepath = "{}{}{}".format(os.getcwd(), os.sep, filename) + if os.path.isfile(filepath) is True: + result.append(filepath) + + # Return + return result + + +def _filepaths_in_directories(directories): + """Create a list of full file paths based on input directories. + + Args: + directories: A list of directories + + Returns: + result: A list of full file paths + + """ + # Initialize key variables + result = [] + + # Iterate and analyze each directory + for directory in directories: + for root, _, files in os.walk(directory, topdown=False): + for name in files: + # Read each file and count the lines found + result.append(os.path.join(root, name)) + # Return + return result + + +def _arg_parser_resolver(): + """Resolve the CLI arguments provided by the user. + + Args: + None + + Returns: + result: Parsed argument object + + """ + # Initialize parser and add the CLI options we should expect + parser = argparse.ArgumentParser() + parser.add_argument( + "--lines", + type=int, + required=False, + default=300, + help="The maximum number of lines of code to accept.", + ) + parser.add_argument( + "--directory", + type=str, + required=False, + default=os.getcwd(), + help="The parent directory of files to analyze.", + ) + parser.add_argument( + "--exclude_files", + type=str, + required=False, + nargs="*", + default=None, + const=None, + help="""An optional space separated list of \ +files to exclude from the analysis.""", + ) + parser.add_argument( + "--exclude_directories", + type=str, + required=False, + nargs="*", + default=None, + const=None, + help="""An optional space separated list of \ +directories to exclude from the analysis.""", + ) + + # Return parser + result = parser.parse_args() + return result + + +def main(): + """Analyze dart files. + + This function finds, and prints the files that exceed the CLI + defined defaults. + + Args: + None + + Returns: + None + + """ + # Initialize key variables + lookup = {} + errors_found = False + file_count = 0 + Excludes = namedtuple("Excludes", "files directories") + + # Get the CLI arguments + args = _arg_parser_resolver() + + # Define the directories of interest + directories = [ + os.path.expanduser(os.path.join(args.directory, "lib")), + os.path.expanduser(os.path.join(args.directory, "src")), + os.path.expanduser(os.path.join(args.directory, "test")), + ] + + # Get a corrected list of filenames to exclude + exclude_list = _valid_exclusions( + Excludes( + files=args.exclude_files, directories=args.exclude_directories + ) + ) + + # Get interesting filepaths + repo_filepath_list = _filepaths_in_directories(directories) + + # Iterate and analyze each directory + for filepath in repo_filepath_list: + # Skip excluded files + if filepath in exclude_list: + continue + + # Skip /node_modules/ sub directories + if "{0}node_modules{0}".format(os.sep) in filepath: + continue + + # Ignore invalid file extensions + if _valid_extension(filepath) is False: + continue + + # Ignore invalid file filenames + if _valid_filename(filepath) is False: + continue + + # Process the rest + with open(filepath, encoding="latin-1") as code: + line_count = sum( + 1 + for line in code + if line.strip() + and not ( + line.strip().startswith("#") + or line.strip().startswith("/") + ) + ) + lookup[filepath] = line_count + + # If the line rule is voilated then the value is changed to 1 + for filepath, line_count in lookup.items(): + if line_count > args.lines: + errors_found = True + file_count += 1 + if file_count == 1: + print( + """ +LINE COUNT ERROR: Files with excessive lines of code have been found\n""" + ) + + print(" Line count: {:>5} File: {}".format(line_count, filepath)) + + # Evaluate and exit + if bool(errors_found) is True: + print( + """ +The {} files listed above have more than {} lines of code. + +Please fix this. It is a pre-requisite for pull request approval. +""".format( + file_count, args.lines + ) + ) + sys.exit(1) + else: + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/eslint_disable_check.py b/.github/workflows/eslint_disable_check.py new file mode 100644 index 0000000000..1efa49feb4 --- /dev/null +++ b/.github/workflows/eslint_disable_check.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +"""ESLint Checker Script. + +Methodology: + + Recursively analyzes TypeScript files in the 'src' directory and its subdirectories + as well as 'setup.ts' files to ensure they do not contain eslint-disable statements. + + This script enforces code quality practices in the project. + +NOTE: + + This script complies with our python3 coding and documentation standards. + It complies with: + + 1) Pylint + 2) Pydocstyle + 3) Pycodestyle + 4) Flake8 + +""" + +import os +import re +import argparse +import sys + +def has_eslint_disable(file_path): + """ + Check if a TypeScript file contains eslint-disable statements. + + Args: + file_path (str): Path to the TypeScript file. + + Returns: + bool: True if eslint-disable statement is found, False otherwise. + """ + with open(file_path, 'r') as file: + content = file.read() + return re.search(r'//\s*eslint-disable', content) + +def check_eslint(directory): + """ + Recursively check TypeScript files for eslint-disable statements in the 'src' directory. + + Args: + directory (str): Path to the directory. + + Returns: + bool: True if eslint-disable statement is found, False otherwise. + """ + eslint_found = False + + for root, dirs, files in os.walk(os.path.join(directory, 'src')): + for file_name in files: + if file_name.endswith('.tsx') and not file_name.endswith('.test.tsx'): + file_path = os.path.join(root, file_name) + if has_eslint_disable(file_path): + print(f'File {file_path} contains eslint-disable statement.') + eslint_found = True + + setup_path = os.path.join(directory, 'setup.ts') + if os.path.exists(setup_path) and has_eslint_disable(setup_path): + print(f'Setup file {setup_path} contains eslint-disable statement.') + eslint_found = True + + return eslint_found + +def arg_parser_resolver(): + """Resolve the CLI arguments provided by the user. + + Returns: + result: Parsed argument object + + """ + parser = argparse.ArgumentParser() + parser.add_argument( + "--directory", + type=str, + default=os.getcwd(), + help="Path to the directory to check (default: current directory)" + ) + return parser.parse_args() + +def main(): + """ + Execute the script's main functionality. + + This function serves as the entry point for the script. It performs + the following tasks: + 1. Validates and retrieves the directory to check from + command line arguments. + 2. Recursively checks TypeScript files for eslint-disable statements. + 3. Provides informative messages based on the analysis. + 4. Exits with an error if eslint-disable statements are found. + + Raises: + SystemExit: If an error occurs during execution. + """ + + args = arg_parser_resolver() + + if not os.path.exists(args.directory): + print(f"Error: The specified directory '{args.directory}' does not exist.") + sys.exit(1) + + # Check eslint in the specified directory + eslint_found = check_eslint(args.directory) + + if eslint_found: + print("ESLint-disable check failed. Exiting with error.") + sys.exit(1) + + print("ESLint-disable check completed successfully.") + +if __name__ == "__main__": + main() diff --git a/.github/workflows/issue.yml b/.github/workflows/issue.yml index 798c766ca6..06da465ccf 100644 --- a/.github/workflows/issue.yml +++ b/.github/workflows/issue.yml @@ -1,13 +1,35 @@ -name: Issue Auto label +############################################################################## +############################################################################## +# +# NOTE! +# +# Please read the README.md file in this directory that defines what should +# be placed in this file +# +############################################################################## +############################################################################## + +name: Issue Workflow on: issues: types: ['opened'] jobs: - build: + Opened-issue-label: + name: Adding Issue Label runs-on: ubuntu-latest steps: - - uses: Renato66/auto-label@v2.2.0 + - uses: Renato66/auto-label@v2.3.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} ignore-comments: true default-labels: '["unapproved"]' + + Issue-Greeting: + name: Greeting Message to User + runs-on: ubuntu-latest + steps: + - uses: actions/first-interaction@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + issue-message: "Congratulations on making your first Issue! :confetti_ball: If you haven't already, check out our [Contributing Guidelines](https://github.com/PalisadoesFoundation/talawa-admin/blob/develop/CONTRIBUTING.md) and [Issue Reporting Guidelines](https://github.com/PalisadoesFoundation/talawa-admin/blob/develop/ISSUE_GUIDELINES.md) to ensure that you are following our guidelines for contributing and making issues." + diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml deleted file mode 100644 index cae9570993..0000000000 --- a/.github/workflows/linter.yml +++ /dev/null @@ -1,11 +0,0 @@ -name: Linter -on: [pull_request] -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Install Dependencies - run: yarn - - name: Run ESLint and Prettier - run: yarn lint \ No newline at end of file diff --git a/.github/workflows/md_mdx_format_adjuster.py b/.github/workflows/md_mdx_format_adjuster.py new file mode 100644 index 0000000000..c33ad1fa66 --- /dev/null +++ b/.github/workflows/md_mdx_format_adjuster.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +""" +Script to make Markdown files MDX compatible. + +This script scans Markdown files and escapes special characters (<, >, {, }) +to make them compatible with the MDX standard used in Docusaurus v3. + +This script complies with: + 1) Pylint + 2) Pydocstyle + 3) Pycodestyle + 4) Flake8 +""" + +import os +import argparse +import re + +def escape_mdx_characters(text): + """ + Escape special characters in a text string for MDX compatibility. + Avoids escaping already escaped characters. + + Args: + text: A string containing the text to be processed. + + Returns: + A string with special characters (<, >, {, }) escaped, avoiding + double escaping. + """ + # Regular expressions to find unescaped special characters + patterns = { + "<": r"(?": r"(?", + "{": r"(? 100 + env: + CHANGED_FILES_COUNT: ${{ steps.changed-files.outputs.all_changed_files_count }} + run: | + echo "Error: Too many files (greater than 100) changed in the pull request." + echo "Possible issues:" + echo "- Contributor may be merging into an incorrect branch." + echo "- Source branch may be incorrect please use develop as source branch." + exit 1 + + Check-ESlint-Disable: + name: Check for eslint-disable + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: 3.9 + + - name: Run Python script + run: | + python .github/workflows/eslint_disable_check.py + + Test-Application: + name: Test Application + runs-on: ubuntu-latest + needs: [Code-Quality-Checks, Check-ESlint-Disable] + steps: + - name: Checkout the Repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - name: Install Dependencies + run: npm install + + - name: Get changed TypeScript files + id: changed-files + uses: tj-actions/changed-files@v40 + + - name: Run tests + if: steps.changed-files.outputs.only_changed != 'true' + run: npm run test -- --watchAll=false --coverage + + - name: TypeScript compilation for changed files + run: | + for file in ${{ steps.changed-files.outputs.all_files }}; do + if [[ "$file" == *.ts || "$file" == *.tsx ]]; then + 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 + fail_ci_if_error: false + name: '${{env.CODECOV_UNIQUE_NAME}}' + + - name: Test acceptable level of code coverage + uses: VeryGoodOpenSource/very_good_coverage@v2 + with: + path: "./coverage/lcov.info" + min_coverage: 95.0 + + Graphql-Inspector: + 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: '20.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' + + Check-Target-Branch: + name: Check Target Branch + runs-on: ubuntu-latest + steps: + - name: Check if the target branch is develop + if: github.event.pull_request.base.ref != 'develop' + run: | + echo "Error: Pull request target branch must be 'develop'. Please refer PR_GUIDELINES.md" + exit 1 + diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml new file mode 100644 index 0000000000..0542490787 --- /dev/null +++ b/.github/workflows/push.yml @@ -0,0 +1,185 @@ +############################################################################## +############################################################################## +# +# NOTE! +# +# Please read the README.md file in this directory that defines what should +# be placed in this file +# +############################################################################## +############################################################################## + +name: push workflow + +on: + push: + branches: + - '**' + +env: + CODECOV_UNIQUE_NAME: CODECOV_UNIQUE_NAME-${{ github.run_id }}-${{ github.run_number }} + +jobs: + Code-Coverage: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20.x] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Cache node modules + id: cache-npm + uses: actions/cache@v4 + env: + cache-name: cache-node-modules + with: + path: | + ~/.npm + node_modules + key: ${{ runner.os }}-code-coverage-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-code-coverage-${{ env.cache-name }}- + ${{ runner.os }}-code-coverage- + ${{ runner.os }}- + + - if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }} + name: List the state of node modules + 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 + with: + token: ${{ secrets.CODECOV_TOKEN }} + verbose: true + fail_ci_if_error: false + name: '${{env.CODECOV_UNIQUE_NAME}}' + + Generate-Documentation: + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/automated-docs' + steps: + - name: Checkout the Repository + uses: actions/checkout@v4 + # with: + # ref: develop + + # - name: Pull latest changes from develop + # run: git pull origin develop + + - name: Node.js Version + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Restore node_modules from cache + id: cache-npm + uses: actions/cache@v4 + env: + cache-name: cache-node-modules + with: + path: | + ~/.npm + node_modules + key: ${{ runner.os }}-generate-docs-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-generate-docs-${{ env.cache-name }}- + ${{ runner.os }}-generate-docs- + ${{ runner.os }}- + + - name: Install dependencies + run: npm install + + - name: Install TypeScript Globally and add GraphQL tag + run: yarn global add typescript + - run: yarn add graphql-tag + + - name: Update Dependencies + run: yarn upgrade + + - name: Generate Documentation of Markdown pages + run: | + npm install --global typedoc + npm install typedoc-plugin-markdown + npm install --save-dev @types/node + npx typedoc --entryPoints src/components src/screens --out talawa-admin-docs --plugin typedoc-plugin-markdown --theme markdown --entryPointStrategy expand --exclude "**/*.test.ts" --exclude "**/*.css" + + - name: Make Markdown Files MDX Compatible + run: python ./.github/workflows/md_mdx_format_adjuster.py --directory talawa-admin-docs + + + - name: Checking doc updated + id: DocUpdated + run: | + if [ -n "$(git status --porcelain)" ]; then + echo "updateDoc=true" >> $GITHUB_OUTPUT + echo -e "Documentation has been updated!!" + else + Green='0;32' + NoColor='\033[0m' + echo -e "${Green}No documentation updated${NoColor}" + fi + + - name: Set env variables + if: steps.DocUpdated.outputs.updateDoc + run: | + echo "commit_id=$(echo $(git rev-parse HEAD))" >> $GITHUB_ENV + echo "email=$(echo $(git log --pretty=format:"%ae" $commit_id))" >> $GITHUB_ENV + + - name: Update Doc + if: steps.DocUpdated.outputs.updateDoc + run: | + Green='0;32' + NoColor='\033[0m' + git config --global user.name "${{github.actor}}" + git config --global user.email "${{env.email}}" + git add . + git commit -m "Update documentation" + git push origin develop:automated-docs --force + echo -e "🚀${Green} Hurrah! doc updated${NoColor}" + + - name: Create Documentation Artifact + uses: actions/upload-artifact@v2 + with: + name: documentation-admin + path: talawa-admin-docs + + Empty-Commit: + name: Create Empty Commit + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/develop' + needs: Generate-Documentation + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + persist-credentials: false + token: ${{ secrets.TALAWA_DOCS_SYNC }} + - name: Empty Commit + run: | + git config --global user.name "${{github.actor}}" + git config --global user.email "${{env.email}}" + git config --global url.https://${{ secrets.TALAWA_DOCS_SYNC }}@github.com/.insteadOf https://github.com/ + git commit --allow-empty -m "Trigger Documentation Workflow" + git push origin develop:automated-docs --force + + Copy-docs-to-talawa-docs: + if: github.ref == 'refs/heads/automated-docs' + needs: Generate-Documentation + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dmnemec/copy_file_to_another_repo_action@v1.1.1 + env: + API_TOKEN_GITHUB: ${{secrets.TALAWA_DOCS_SYNC}} + with: + source_file: 'talawa-admin-docs/' + destination_repo: 'PalisadoesFoundation/talawa-docs' + destination_branch: 'develop' + destination_folder: 'docs/' + user_email: '${{env.email}}' + user_name: '${{github.actor}}' + commit_message: 'Talawa Admin docs updated' diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000000..24667f8e06 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,43 @@ +############################################################################## +############################################################################## +# +# NOTE! +# +# Please read the README.md file in this directory that defines what should +# be placed in this file +# +############################################################################## +############################################################################## + +name: Mark stale issues and pull requests + +on: + schedule: + - cron: "0 0 * * *" + +permissions: + issues: write + pull-requests: write + +jobs: + stale: + + runs-on: ubuntu-latest + + steps: + - uses: actions/stale@v8 + 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.' + stale-pr-message: 'This pull request did not get any activity in the past 10 days and will be closed in 180 days if no update occurs. Please verify it has no conflicts with the develop branch and rebase if needed. Mention it now if you need help or give permission to other people to finish your work.' + close-issue-message: 'This issue did not get any activity in the past 180 days and thus has been closed. Please check if the newest release or develop branch has it fixed. Please, create a new issue if the issue is not fixed.' + close-pr-message: 'This pull request did not get any activity in the past 180 days and thus has been closed.' + stale-issue-label: 'no-issue-activity' + stale-pr-label: 'no-pr-activity' + days-before-stale: 10 + days-before-close: 180 + remove-stale-when-updated: true + exempt-all-milestones: true + exempt-pr-labels: 'wip' + exempt-issue-labels: 'wip' + operations-per-run: 30 diff --git a/.gitignore b/.gitignore index 4d29575de8..80c2b97cd9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,24 @@ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. +# files that interfere with YARN +yarn.lock +pnpm-lock.yaml + # dependencies /node_modules /.pnp .pnp.js # testing -/coverage +coverage/ +codecov # production /build # misc .DS_Store +.env .env.local .env.development.local .env.test.local @@ -21,3 +27,11 @@ npm-debug.log* yarn-debug.log* yarn-error.log* + +# express setup +debug.log + +# No editor related files +.idea +.vscode +*.swp diff --git a/.husky/post-merge b/.husky/post-merge new file mode 100755 index 0000000000..c7f42c373b --- /dev/null +++ b/.husky/post-merge @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +git diff HEAD^ HEAD --exit-code -- ./package.json || npm install \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000000..c9c109cceb --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,10 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +# npm run format:fix +# npm run lint:fix +npm run lint-staged +npm run typecheck +npm run update:toc + +git add . diff --git a/.lintstagedrc.json b/.lintstagedrc.json new file mode 100644 index 0000000000..36195c0491 --- /dev/null +++ b/.lintstagedrc.json @@ -0,0 +1,5 @@ +{ + "**/*.{ts,tsx,yml}": "eslint --fix", + "**/*.{ts,tsx,json,scss,css,yml}": "prettier --write", + "**/*.{ts,tsx}": "node scripts/githooks/check-localstorage-usage.js" +} diff --git a/.node-version b/.node-version new file mode 100644 index 0000000000..790e1105f2 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +v20.10.0 diff --git a/.prettierignore b/.prettierignore index 9a357a08f7..a955d32db3 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,4 @@ node_modules -.github \ No newline at end of file +.github +# Contains the PDF file of the Tag as JSON string, thus does not need to be formatted +src/components/CheckIn/tagTemplate.ts \ No newline at end of file diff --git a/.prettierrc b/.prettierrc index dc2fb828f0..2c0fc022ce 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,3 +1,4 @@ { - "singleQuote": true + "singleQuote": true, + "endOfLine": "auto" } \ No newline at end of file diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000000..57dc9c6c80 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,2 @@ +/.github/ @palisadoes +CODEOWNERS @palisadoes diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 4a38c46419..b82fab3779 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,5 +1,23 @@ # Contributor Covenant Code of Conduct +# Table of Contents + + + +- [Our Pledge](#our-pledge) +- [Our Standards](#our-standards) +- [Enforcement Responsibilities](#enforcement-responsibilities) +- [Scope](#scope) +- [Enforcement](#enforcement) +- [Enforcement Guidelines](#enforcement-guidelines) + - [1. Correction](#1-correction) + - [2. Warning](#2-warning) + - [3. Temporary Ban](#3-temporary-ban) + - [4. Permanent Ban](#4-permanent-ban) +- [Attribution](#attribution) + + + ## Our Pledge We as members, contributors, and leaders pledge to make participation in our diff --git a/CODE_STYLE.md b/CODE_STYLE.md new file mode 100644 index 0000000000..df184b12a0 --- /dev/null +++ b/CODE_STYLE.md @@ -0,0 +1,253 @@ +# Talawa Admin Code Style + +For Talawa Admin, most of the rules for the code style have been enforced with ESLint, but this document serves to provide an overview of the Code style used in Talawa Admin and the Rationale behind it. + +The code style must be strictly adhered to, to ensure that there is consistency throughout the contributions made to Talawa-Admin + +code style should not be changed and must be followed. + +# Table of Contents + + + +- [Tech Stack](#tech-stack) +- [Component Structure](#component-structure) +- [Code Style and Naming Conventions](#code-style-and-naming-conventions) +- [Test and Code Linting](#test-and-code-linting) +- [Folder/Directory Structure](#folderdirectory-structure) + - [Sub Directories of `src`](#sub-directories-of-src) +- [Imports](#imports) +- [Customising Bootstrap](#customising-bootstrap) + + + +## Tech Stack + +- Typescript + +- React.js + +- CSS module + +- React bootstrap + +- Material UI + +- GraphQL + +- Jest & React Testing Library for testing + +## Component Structure + +- Components should be strictly functional components + +- Should make use of React hooks where appropriate + + +## Code Style and Naming Conventions + +- All React components *must* be written in PascalCase, with their file names, and associated CSS modules being written in PascalCase + +- All other files may follow the camelCase naming convention + +- All the Return fragment should be closed in empty tag + +- Use of custom classes directly are refrained, use of modular css is encouraged along with bootstrap classes + +**Wrong way ❌** +``` +
...
+
...
// No using personal custom classes directly, here you should not use myCustomClass2 +.container{...} // No changing the property of already existing classes reserved by boostrap directly in css files +``` + +**Correct ways ✅** +``` +
...
// Use custom class defined in modular css file +
...
// Use classes already defined in Bootstrap +
...
// Use classes already defined in Bootstrap +``` + +- All components should be either imported from React-Bootstrap library or Material UI library, components should not be written using plain Bootstrap classes and attributes without leveraging the React-Bootstrap library. + +**Example: Bootstrap Dropdown** + +**Wrong way ❌** + +Using plain Bootstrap classes and attributes without leveraging the React-Bootstrap library should be refrained. While it may work for basic functionality, it doesn't fully integrate with React and may cause issues when dealing with more complex state management or component interactions. +``` + +``` + + +**Correct way ✅** + +It's recommended to use the React-Bootstrap library for seamless integration of Bootstrap components in a React application. +``` +import Dropdown from 'react-bootstrap/Dropdown'; + +function BasicExample() { + return ( + + + Dropdown Button + + + + Action + Another action + Something else + + + ); +} + +export default BasicExample; +``` + + +## Test and Code Linting + +Unit tests must be written for *all* code submissions to the repository, +the code submitted must also be linted ESLint and formatted with Prettier. + +## Folder/Directory Structure + +### Sub Directories of `src` + +`assets` - This houses all of the static assets used in the project + - `css` - This houses all of the css files used in the project + - `images` - This houses all of the images used in the project + - `scss` - This houses all of the scss files used in the project + - `components -` All Sass files for components + - `content -` All Sass files for content + - `forms -` All Sass files for forms + - `_talawa.scss` - Partial Sass file for Talawa + - `_utilities.scss` - Partial Sass file for utilities + - `_variables.scss` - Partial Sass file for variables + - `app.scss` - Main Sass file for the app, imports all other partial Sass files + +`components` - The directory for base components that will be used in the various views/screens + +`Constant` - This houses all of the constants used in the project + +`GraphQl` - This houses all of the GraphQL queries and mutations used in the project + +`screens` - This houses all of the views/screens to be navigated through in Talawa-Admin + +`state` - This houses all of the state management code for the project + +`utils` - This holds the utility functions that do not fall into any of the other categories + + +## Imports + +Absolute imports have been set up for the project, so imports may be done directly from `src`. + +An example being + +``` +import Navbar from 'components/Navbar/Navbar'; +``` + +Imports should be grouped in the following order: + + - React imports + - Third party imports + - Local imports + + +If there is more than one import from a single library, they should be grouped together + +Example - If there is single import from a library, both ways will work + +``` +import Row from 'react-bootstrap/Row'; +// OR +import { Row } from 'react-bootstrap'; +``` + +If there are multiple imports from a library, they should be grouped together + +``` +import { Row, Col, Container } from 'react-bootstrap'; +``` + +## Customising Bootstrap + +Bootstrap v5.3.0 is used in the project. +Follow this [link](https://getbootstrap.com/docs/5.3/customize/sass/) to learn how to customise bootstrap. + +**File Structure** + +- `src/assets/scss/components/{'{partialFile}'}.scss` - where the {'{partialFile}'} are the following files + - **_accordion.scss** + - **_alert.scss** + - **_badge.scss** + - **_breadcrumb.scss** + - **_buttons.scss** + - **_card.scss** + - **_carousel.scss** + - **_close.scss** + - **_dropdown.scss** + - **_list-group.scss** + - **_modal.scss** + - **_nav.scss** + - **_navbar.scss** + - **_offcanvas.scss** + - **_pagination.scss** + - **_placeholder.scss** + - **_progress.scss** + - **_spinners.scss** + +- `src/assets/scss/content/{'{partialFile}'}.scss` - where the {'{partialFile}'} are the following files + - **_table.scss** + - **_typography.scss** + + +- `src/assets/scss/forms/{'{partialFile}'}.scss` - where the {'{partialFile}'} are the following files + - **_check-radios.scss** + - **_floating-label.scss** + - **_form-control.scss** + - **_input-group.scss** + - **_range.scss** + - **_select.scss** + - **_validation.scss** + +- `src/assets/scss/_utilities.scss` - The utility API is a Sass-based tool to generate utility classes. +- `src/assets/scss/_variables.scss` - This file contains all the Sass variables used in the project +- `src/assets/scss/_talawa.scss` - This files contains all the partial Sass files imported into it + +**How to compile Sass file** + +`src/assets/scss/app.scss` is the main Sass file for the app, it imports all other partial Sass files. +According to naming convention the file name of the partial Sass files should start with an underscore `_` and end with `.scss`, these partial Sass files are not meant to be compiled directly, they are meant to be imported into another Sass file. Only the main Sass file `src/assets/scss/app.scss` should be compiled. + +The compiled CSS file is `src/assets/css/app.css` and it is imported into `src/index.tsx` file. + +To compile the Sass file once, run the following command in the terminal + +``` +npx sass src/assets/scss/app.scss src/assets/css/app.css +``` + +To watch the Sass file for changes and compile it automatically, run the following command in the terminal + +``` +npx sass src/assets/scss/app.scss src/assets/css/app.css --watch +``` +The `src/assets/css/app.css.map` file associates the generated CSS code with the original SCSS code. It allows you to see your SCSS code in the browser's developer tools for debugging. + +To skip generating the map file, run +``` +npx sass --no-source-map src/assets/scss/app.scss src/assets/css/app.css +``` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d4a02270b6..47fa8d6e69 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,25 +4,44 @@ Thank you for your interest in contributing to Talawa Admin. Regardless of the s If you are new to contributing to open source, please read the Open Source Guides on [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/). +## Table of Contents + + + +- [Code of Conduct](#code-of-conduct) +- [Ways to Contribute](#ways-to-contribute) + - [Our Development Process](#our-development-process) + - [Issues](#issues) + - [Pull Requests](#pull-requests) + - [Branching Strategy](#branching-strategy) + - [Conflict Resolution](#conflict-resolution) + - [Contributing Code](#contributing-code) +- [Internships](#internships) +- [Community](#community) + + + ## Code of Conduct -A safe environment is required for everyone to contribute. Read our [Code of Conduct Guide](https://github.com/PalisadoesFoundation/talawa-admin/blob/master/CODE_OF_CONDUCT.md) to understand what this means. Let us know immediately if you have unacceptable experiences in this area. +A safe environment is required for everyone to contribute. Read our [Code of Conduct Guide](CODE_OF_CONDUCT.md) to understand what this means. Let us know immediately if you have unacceptable experiences in this area. No one should fear voicing their opinion. Respones must be respectful. ## Ways to Contribute -If you are ready to start contributing code right away, we have a list of [good first issues](https://github.com/PalisadoesFoundation/talawa-admin/labels/good%20first%20issue) that contain issues with a limited scope. +If you are ready to start contributing code right away, get ready! -## Quicklinks +1. Join our Slack and introduce yourself. See details on how to join below in the Community section. + 1. This repository has its own dedicated channel. + 1. There are many persons on the various channels who are willing to assist you in getting started. +1. Take a look at our issues (**_after reading our guidelines below_**): + 1. We have a list of [good first issues](https://github.com/PalisadoesFoundation/talawa-admin/labels/good%20first%20issue) that contain challenges with a limited scope for beginners. + 1. There are issues for creating tests for our code base. We need to increase reliablility. Try those issues, or create your own for files that don't already have tests. This is another good strategy for beginners. + 1. There are [dormant issues on which nobody has worked for some time](https://github.com/PalisadoesFoundation/talawa-admin/issues?q=is%3Aopen+is%3Aissue+label%3Ano-issue-activity). These are another place to start + 1. There may also be [dormant PRs on which nobody has worked for some time](https://github.com/PalisadoesFoundation/talawa-admin/issues?q=is%3Aopen+is%3Aissue+label%3Ano-issue-activity+label%3Ano-pr-activity)! +1. Create an issue based on a bug you have found or a feature you would like to add. We value meaningful sugestions and will prioritize them. -- [Our Development Process](#Our-development-process) - - [Issues](#issues) - - [Pull Requests](#pull-requests) - - [Git Flow](#git-flow) -- [Contributing Code](#contributing-code) -- [GSoC](#gsoc) -- [Community](#community) +Welcome aboard! ### Our Development Process @@ -30,24 +49,27 @@ We utilize GitHub issues and pull requests to keep track of issues and contribut #### Issues -Make sure you are following [issue report guidelines](https://github.com/PalisadoesFoundation/talawa-admin/blob/master/issue-guidelines.md) available here before creating any new issues on Talawa Admin project. +Make sure you are following [issue report guidelines](ISSUE_GUIDELINES.md) available here before creating any new issues on Talawa Admin project. #### Pull Requests -[Pull Request guidelines](https://github.com/PalisadoesFoundation/talawa-admin/blob/master/PR-guidelines.md) is best resource to follow to start working on open issues. +[Pull Request guidelines](PR_GUIDELINES.md) is best resource to follow to start working on open issues. + +#### Branching Strategy -#### Git Flow +For Talawa Admin, we had employed the following branching strategy to simplify the development process and to ensure that only stable code is pushed to the `main` branch: -For Talawa Admin, we utilize the GitFlow branching model. GitFlow is geared towards efficiently tracking development and managing releases. The model makes parallel development efforts easy and safe by isolating new development efforts from completed work. +- `develop`: For unstable code and bug fixing +- `main`: Where the stable production ready code lies. This is our default branch. -The different types of branches we may use are: +#### Conflict Resolution -- Feature branches (feature/branch-name) -- Release branches (release/1.XX) -- Bug branches (bugfix/branch-name) -- Hotfix branches (hotfix/branch-name) +When multiple developers are working on issues there is bound to be a conflict of interest (not to be confused with git conflicts) among issues, PRs or even ideas. Usually these conflicts are resolved in a **First Come First Serve** basis however there are certain exceptions to it. -Detailed document containing how GitFlow works: https://nvie.com/posts/a-successful-git-branching-model/ +- In the cases where you feel your potential issues could be an extension or in conflict with other PRs it is important to ask the author of the PR in the slack channel or in their PRs or issues themselves why he/she did not write code for something that would require minimal effort on their part. +- Based on basic courtesy, it is good practice to let the person who created a function apply and test that function when needed. +- Last but not the least, communication is important make sure to talk to other contributors, in these cases, in slack channel or in a issue/PR thread. +- As a last resort the Admins would be responsible for deciding how to resolve this conflict. ### Contributing Code @@ -57,11 +79,81 @@ Make sure you have read the [Documentation for Setting up the Project](https://g The process of proposing a change to Talawa Admin can be summarized as: -1. Fork the Talawa Admin repository and branch off `master`. -1. The repository can be cloned locally using `git clone `. +1. Fork the Talawa Admin repository and branch off `develop`. +1. Your newly forked repository can be cloned locally using `git clone `. +1. Make the Palisadoes Foundation's repo your `git upstream` for your local repo. 1. Make the desired changes to the Talawa Admin project. 1. Run the app and test your changes. -1. If you've added code that should be tested, write tests. +1. If you've added code, then test suites must be added. + + 1. **_General_:** + + 1. We need to get to 100% test coverage for the app. We periodically increase the desired test coverage for our pull requests to meet this goal. + 1. Pull requests that don't meet the minimum test coverage levels will not be accepted. This may mean that you will have to create tests for code you did not write. You can decide which part of the code base needs additional tests if this happens to you. + + 2. **_Testing_:** + + 1. Test using this set of commands: + + ``` + npm install + npm run test --watchAll=false --coverage + ``` + + 2. Debug tests in browser + + You can see the output of failing tests in broswer by running `jest-preview` package before running your tests + + ``` + npm install + npm run jest-preview + npm run test --watchAll=false --coverage + ``` + + 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 - + + ![Debugging Test Demo](./public/images/jest-preview.webp) + + 3. **_Test Code Coverage_:** + + 1. _General Information_ + 1. The current code coverage of the repo is: [![codecov](https://codecov.io/gh/PalisadoesFoundation/talawa-admin/branch/develop/graph/badge.svg?token=II0R0RREES)](https://codecov.io/gh/PalisadoesFoundation/talawa-admin) + 2. You can determine the percentage test coverage of your code by running these two commands in sequence: + ``` + npm install + npm run test --watchAll=false --coverage + genhtml coverage/lcov.info -o coverage + ``` + 3. The output of the `npm run test` command will give you a tablular coverage report per file + 4. The overall coverage rate will be visible on the penultimate line of the `genhtml` command's output. + 5. The `genhtml` command is part of the Linux `lcov` package. Similar packages can be found for Windows and MacOS. + 6. The currently acceptable coverage rate can be found in the [GitHub Pull Request file](.github/workflows/pull-requests.yml). Search for the value below the line containing `min_coverage`. + 2. _Testing Individual Files_ + 1. You can test an individual file by running this command: + ``` + npm run test --watchAll=false /path/to/test/file + ``` + 2. You can get the test coverage report for that file by running this command. The report will list all tests in the suite. Those tests that are not run will have zero values. You will need to look for the output line relevant to your test file. + ``` + npm run test --watchAll=false --coverage /path/to/test/file + ``` + 3. _Creating your code coverage account_ + + 1. You can also see your code coverage online for your fork of the repo. This is provided by `codecov.io` + + 1. Go to this link: `https://app.codecov.io/gh/XXXX/YYYY` where XXXX is your GitHub account username and YYYY is the name of the repository + 2. Login to `codecov.io` using your GitHub account, and add your **repo** and **branches** to the `codecov.io` dashboard. + ![Debugging Test Demo](/public/images/codecov/authorise-codecov-github.jpg) + 3. Remember to add the `Repository Upload Token` for your forked repo. This can be found under `Settings` of your `codecov.io` account. + + 4. Click on Setup Repo option + ![Debugging Test Demo]() + 5. Use the value of this token to create a secret named CODE_COV for your forked repo. + [![Code-cov-token.jpg](/public/images/codecov/Code-cov-token.jpg)]() + [![addd-your-key.jpg](/public/images/codecov/addd-your-key.jpg)]() + 6. You will see your code coverage reports with every push to your repo after following these steps + [![results.jpg](/public/images/codecov/results.jpg)]() + 1. After making changes you can add them to git locally using `git add `(to add changes only in a particular file) or `git add .` (to add all changes). 1. After adding the changes you need to commit them using `git commit -m ''`(look at the commit guidelines below for commit messages). 1. Once you have successfully commited your changes, you need to push the changes to the forked repo on github using: `git push origin `.(Here branch name must be name of the branch you want to push the changes to.) @@ -69,18 +161,13 @@ The process of proposing a change to Talawa Admin can be summarized as: 1. Ensure the test suite passes, either locally or on CI once a PR has been created. 1. Review and address comments on your pull request if requested. -### Internships - -We have internship partnerships with a number of organizations. See below for more details. - -#### GSoC - -If you are participating in the 2021 Summer of Code, please read more about us and our processes [here](https://palisadoesfoundation.github.io/talawa-docs/docs/internships/gsoc/gsoc-introduction) +## Internships -#### GitHub Externship +If you are participating in any of the various internship programs we are members of, then please read the [introduction guides on our documentation website](https://docs.talawa.io/docs/). -If you are participating in the 2021 GitHub Externship, please read more about us and our processes [here](https://palisadoesfoundation.github.io/talawa-docs/docs/internships/github/github-introduction) +## Community -### Community +There are many ways to communicate with the community. -The Palisadoes Foundation has a Slack channel where members can assist with support and clarification. Click [here](https://join.slack.com/t/thepalisadoes-dyb6419/shared_invite/zt-nk79xxlg-OxTdlrD7RLaswu8EO_Q5rg) to join our slack channel. +1. The Palisadoes Foundation has a Slack channel where members can assist with support and clarification. Visit the [Talawa GitHub repository home page](https://github.com/PalisadoesFoundation/talawa) for the link to join our slack channel. +1. We also have a technical email list run by [freelists.org](https://www.freelists.org/). Search for "palisadoes" and join. Members on this list are also periodically added to our marketing email list that focuses on less technical aspects of our work. diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md new file mode 100644 index 0000000000..7691b5d452 --- /dev/null +++ b/DOCUMENTATION.md @@ -0,0 +1,32 @@ +# Documentation +Welcome to our documentation guide. Here are some useful tips you need to know! + +# Table of Contents + + + +- [Where to find our documentation](#where-to-find-our-documentation) +- [How to use Docusaurus](#how-to-use-docusaurus) +- [Other information](#other-information) + + + +## Where to find our documentation + +Our documentation can be found in ONLY TWO PLACES: + +1. ***Inline within the repository's code files***: We have automated processes to extract this information and place it in our Talawa documentation site [docs.talawa.io](https://docs.talawa.io/). +1. ***In our `talawa-docs` repository***: Our [Talawa-Docs](https://github.com/PalisadoesFoundation/talawa-docs) repository contains user edited markdown files that are automatically integrated into our Talawa documentation site [docs.talawa.io](https://docs.talawa.io/) using the [Docusaurus](https://docusaurus.io/) package. + +## How to use Docusaurus +The process in easy: +1. Install `talawa-docs` on your system +1. Launch docusaurus on your system according to the `talawa-docs`documentation. + - A local version of `docs.talawa.io` should automatically launched in your browser at http://localhost:3000/ +1. Add/modify the markdown documents to the `docs/` directory of the `talawa-docs` repository +1. If adding a file, then you will also need to edit the `sidebars.js` which is used to generate the [docs.talawa.io](https://docs.talawa.io/) menus. +1. Always monitor the local website in your brower to make sure the changes are acceptable. + - You'll be able to see errors that you can use for troubleshooting in the CLI window you used to launch the local website. + +## Other information +***PLEASE*** do not add markdown files in this repository. Add them to `talawa-docs`! diff --git a/Docker_Container/.dockerignore b/Docker_Container/.dockerignore deleted file mode 100644 index 56e8146402..0000000000 --- a/Docker_Container/.dockerignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules -build -.dockerignore -Dockerfile -Dockerfile.prod \ No newline at end of file diff --git a/Docker_Container/README.md b/Docker_Container/README.md deleted file mode 100644 index b4bc5bf290..0000000000 --- a/Docker_Container/README.md +++ /dev/null @@ -1,50 +0,0 @@ -## Steps to start the build with Docker - -### Project Setup - -- Install [Docker](https://www.docker.com/) - -- Build and Tag The Docker Image - -`$ docker build -t sample:dev` - -- Then Spin up the container once build is done - -``` -$ docker run \ - -it \ - --rm \ - -v ${PWD}:/app \ - -v /app/node_modules \ - -p 3001:3000 \ - -e CHOKIDAR_USEPOLLING=true \ - sample:dev -``` - -- Whats Happening here - -1. The `docker run` command creates and runs a new conatiner instance from the image we just created - -2. `-it` starts the container in interactive mode - -3. `--rm` removes the container and volumes after the container exists. - -4. `-v ${PWD}:/app` mounts the code into the container at "/app". - -5. Since we want to use the container version of the “node_modules” folder, we configured another volume: `-v /app/node_modules` . You should now be able to remove the local “node_modules” flavor. - -6. `-p 3001:3000` exposes port 3000 to other Docker containers on the same network (for inter-container communication) and port 3001 to the host. - -7. Finally , `-e CHOKIDAR_USEPOLLING=true` enables a polling mechanism via chokidar (which wraps `fs.watch`, `fs.watchFile`, and `fsevents`) so that hot-reloading will work. - -### For using compose file - -- Build the image and fire up the container - -`$ docker-compose up -d --build` - -- Ensure the app is running in the browser and test hot - reloading again. Bring down the container before moving on - -`$ docker-compose stop` - -- Now your container is ready to run diff --git a/Docker_Container/docker-compose.yml b/Docker_Container/docker-compose.yml deleted file mode 100644 index ad7cad7f48..0000000000 --- a/Docker_Container/docker-compose.yml +++ /dev/null @@ -1,16 +0,0 @@ -version: '3.7' - -services: - - sample: - container_name: sample - build: - context: . - dockerfile: Dockerfile - volumes: - - '.:/app' - - '/app/node_modules' - ports: - - 3001:3000 - environment: - - CHOKIDAR_USEPOLLING=true \ No newline at end of file diff --git a/Docker_Container/dockerfile b/Docker_Container/dockerfile deleted file mode 100644 index 34eca8c102..0000000000 --- a/Docker_Container/dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -# pull official base image -FROM node:13.12.0-alpine - -# set working directory -WORKDIR /app - -# add `/app/node_modules/.bin` to $PATH -ENV PATH /app/node_modules/.bin:$PATH - -# install app dependencies -COPY package.json ./ -COPY yarn.lock ./ -COPY package-lock.json ./ -RUN yarn install --silent -RUN yarn install react-scripts@3.4.1 -g --silent - -# add app -COPY . ./ - -# start app -CMD ["yarn", "start"] diff --git a/INSTALLATION.md b/INSTALLATION.md new file mode 100644 index 0000000000..05ede15d0c --- /dev/null +++ b/INSTALLATION.md @@ -0,0 +1,312 @@ +# Talawa-Admin Installation + +This document provides instructions on how to set up and start a running instance of `talawa-admin` 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 + + + +- [Installation Steps Summary](#installation-steps-summary) +- [Prerequisites](#prerequisites) + - [Install git](#install-git) + - [Setting up this repository](#setting-up-this-repository) + - [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 Steps Summary + +Installation is not difficult, but there are many steps. This is a brief explanation of what needs to be done: + +1. Install `git` +2. Download the code from GitHub using `git` +3. Install `node.js` (Node), the runtime environment the application will need to work. +4. Configure the Node Package Manager (`npm`) to automatically use the correct version of Node for our application. +5. Use `npm` to install TypeScript, the language the application is written in. +6. Install other supporting software such as the database. +7. Configure the application +8. Start the application + +These steps are explained in more detail in the sections that follow. + +# Prerequisites + +In this section we'll explain how to set up all the prerequisite software packages to get you up and running. + +## Install git + +The easiest way to get the latest copies of our code is to install the `git` package on your computer. + +Follow the setup guide for `git` on official [git docs](https://git-scm.com/downloads). Basic `git` knowledge is required for open source contribution so make sure you're comfortable with it. [Here's](https://youtu.be/apGV9Kg7ics) a good tutorial to get started with `git` and `github`. + +## Setting up this repository + +First you need a local copy of `talawa-admin`. Run the following command in the directory of choice on your local system. + +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. +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) + + 2. 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) + + 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 + ``` + +## Install node.js + +Best way to install and manage `node.js` is making use of node version managers. We recommend using `fnm`, which will be described in more detail later. + +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` +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` + +## Install TypeScript + +TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. It adds optional types, classes, and modules to JavaScript, and supports tools for large-scale JavaScript applications. + +To install TypeScript, you can use the `npm` command which comes with `node.js`: + +```bash +npm install -g typescript +``` + +This command installs TypeScript globally on your system so that it can be accessed from any project. + +## Install Required Packages + +Run the following command to install the packages and dependencies required by the app: + +``` +npm install +``` + +The prerequisites are now installed. The next step will be to get the app up and running. + +# 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. + +``` +npm run setup +``` + +All the options in "setup" can be done manually as well and here's how to do it. - [Creating .env file](#creating-env-file) + +## Creating .env file + +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 | + +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. + +## Setting up PORT in .env file + +Add a custom port number for Talawa-Admin development purposes to the variable named `PORT` in the `.env` file. + +## Setting up REACT_APP_TALAWA_URL in .env file + +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/" +``` + +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 + +You may not want to setup reCAPTCHA since the project will still work. Moreover, it is recommended to not set it up in development environment. + +Just skip to the [Post Configuration Steps](#post-configuration-steps) if you don't want to set it up. Else, read the following steps. + +If you want to setup Google reCAPTCHA now, you may refer to the `RECAPTCHA` section in the INSTALLATION.md file found in [Talawa-API repo](https://github.com/PalisadoesFoundation/talawa-api). + +`Talawa-admin` needs the `reCAPTCHA site key` for the `reCAPTCHA` service you set up during `talawa-api` installation as shown in this screenshot: + +![reCAPTCHA site key](./public/images/REACT_SITE_KEY.webp) + +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 + +Set the `ALLOW_LOGS` to "YES" if you want warnings , info and error messages in your console or leave it blank if you dont need them or want to keep the console clean + +# Post Configuration Steps + +It's now time to start Talawa-Admin and get it running + +## Running Talawa-Admin + +Run the following command to start `talawa-admin` development server: + +``` +npm run serve +``` + +## Accessing Talawa-Admin + +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. + +## Talawa-Admin Registration + +The first time you navigate to the running talawa-admin's website you'll land at talawa-admin registration page. Sign up using whatever credentials you want and create the account. Make sure to remember the email and password you entered because they'll be used to sign you in later on. + +## Talawa-Admin Login + +Now sign in to talawa-admin using the `email` and `password` you used to sign up. + +# Testing + +It is important to test our code. If you are a contributor, please follow these steps. + +## Running tests + +You can run the tests for `talawa-admin` using this command: + +``` +npm run test +``` + +## Debugging tests + +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 - + +![Debugging Test Demo](./public/images/jest-preview.webp) + +## Linting code files + +You can lint your code files using this command: + +``` +npm run lint:fix +``` + +## Husky for Git Hooks + +We are using the package `Husky` to run git hooks that run according to different git workflows. + +#### pre-commit hook + +We run a pre-commit hook which automatically runs code quality checks each time you make a commit and also fixes some of the issues. This way you don't have to run them manually each time. + +If you don't want these pre-commit checks running on each commit, you can manually opt out of it using the `--no-verify` flag with your commit message as shown:- + + git commit -m "commit message" --no-verify + +#### post-merge hook + +We are also running a post-merge(post-pull) hook which will automatically run "npm install" only if there is any change made to pakage.json file so that the developer has all the required dependencies when pulling files from remote. + +If you don't want this hook to run, you can manually opt out of this using the `no verify` flag while using the merge command(git pull): + + git pull --no-verify + +
diff --git a/ISSUE_GUIDELINES.md b/ISSUE_GUIDELINES.md new file mode 100644 index 0000000000..5170de5839 --- /dev/null +++ b/ISSUE_GUIDELINES.md @@ -0,0 +1,59 @@ +# Issue Report Guidelines + +:+1::tada: First off, thanks for taking the time to contribute! :tada::+1: + +In order to give everyone a chance to submit a issues reports and contribute to the Talawa project, we have put restrictions in place. This section outlines the guidelines that should be imposed upon issue reports in the Talawa project. + +___ +## Table of Contents + + + +- [Issue Management](#issue-management) + - [New Issues](#new-issues) + - [Existing Issues](#existing-issues) + - [Feature Request Issues](#feature-request-issues) + - [Monitoring the Creation of New Issues](#monitoring-the-creation-of-new-issues) +- [General Guidelines](#general-guidelines) + + + +___ +## Issue Management + +In all cases please use the [GitHub open issue search](https://github.com/PalisadoesFoundation/talawa-admin/issues) to check whether the issue has already been reported. + +### New Issues +To create new issues follow these steps: + +1. Your issue may have already been created. Search for duplicate open issues before submitting yours.for similar deficiencies in the code.duplicate issues are created. +1. Verify whether the issue has been fixed by trying to reproduce it using the latest master or development branch in the repository. +1. Click on the [`New Issue`](https://github.com/PalisadoesFoundation/talawa-admin/issues/new/choose) button +1. Use the templates to create a standardized report of what needs to be done and why. +1. If you want to be assigned the issue that you have created, then add a comment immediately after submitting it. + +We welcome contributors who find new ways to make the code better. + +### Existing Issues + +You can also be a valuable contributor by searching for dormant issues. Here's how you can do that: + +1. **Previously Assigned Issues**: We regularly review issues and add a [`no-issue-activity`](https://github.com/PalisadoesFoundation/talawa-admin/issues?q=is%3Aissue+is%3Aopen+label%3Ano-issue-activity) label to them. Use the issue comments to ask whether the assignee is still working on the issue, and if not, ask for the issue to be assigned to you. +1. **Unassigned Issues**: If the issue is already reported and [not assigned to anyone](https://github.com/PalisadoesFoundation/talawa-admin/issues?q=is%3Aissue+is%3Aopen+no%3Aassignee) and you are interested in working on the issue then: + 1. Ask for the issue to be assigned to you in the issue comments + 2. Ask our contributors to assign it to you in `#talawa` slack channel. + +Working on these types of existing issues is a good way of getting started with the community. + +### Feature Request Issues + +Feature requests are welcome. But take a moment to find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the mentors of the merits of this feature. Please provide as much detail and context as possible. + +### Monitoring the Creation of New Issues +1. Join our `#talawa-github` slack channel for automatic issue and pull request updates. + +## General Guidelines + +1. Discuss issues in our various slack channels when necessary +2. Please do not derail or troll issues. +3. Keep the discussion on topic and respect the opinions of others. diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md deleted file mode 100644 index c59e24c1ee..0000000000 --- a/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,38 +0,0 @@ - - -## Expected Behavior - - - -## Current Behavior - - - -## Possible Solution - - - -## Steps to Reproduce - - - - -1. -2. -3. -4. - -## Context (Environment) - - - - - - -## Detailed Description - - - -## Possible Implementation - - diff --git a/PR-guidelines.md b/PR-guidelines.md deleted file mode 100644 index c469028b0b..0000000000 --- a/PR-guidelines.md +++ /dev/null @@ -1,21 +0,0 @@ -# Pull Request Guidelines - -:+1::tada: First off, thanks for taking the time to contribute! :tada::+1: - -In order to give everyone a chance to submit a pull request and contribute to the Talawa API project, we have put restrictions in place. This section outlines the guidelines that should be imposed upon pull requests in the Talawa API project. - -1. Do not start working on any open issue and raise a PR unless it is assigned to you. -2. Pull requests must be based on [open issues](https://github.com/PalisadoesFoundation/talawa-admin/issues) available. -3. [Use this method to automatically close the issue when the PR is completed.](https://docs.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue) -4. Each contributor may only create one pull request at a time. We have this rule in place due to our limited resources - if everyone was allowed to post multiple pull requests we will not be able to review them properly. It is also better for contributors because you can focus on creating one quality PR - so spend time making sure it is as good as it can be. -5. If the pull request's code quality is not up to par, or it would break the app, it will more likely be closed. So please be careful when creating a PR. -6. Please follow the [PR template](https://github.com/PalisadoesFoundation/talawa-admin/blob/master/templates/pr-template.md). Ensure the PR title clearly describes the problem it is solving. In the description, include the relevant issue number, snapshots and videos after changes added. -7. If you are borrowing code, please disclose it. It is fine and sometimes even recommended to borrow code, but we need to know about it to assess your work. If we find out that your pull request contains a lot of code copied from elsewhere, we will close the pull request. -8. All pull request must have test units. If for some reason it is not possible to add tests, please let us know and explain why. In that case, you'll need to tell us what steps you followed to manually test your changes. -9. No Work In Progress. ONLY completed and working pull requests, and with test units, will be accepted. A WIP would fall under rule 4 and be closed immediately. -10. Please do not @mention contributors and mentors. Sometimes it takes time before we can review your pull request or answer your questions but we'll get to it sooner or later. @mentioning someone just adds to the pile of notifications we get and it won't make us look at your issue faster. -11. Do not force push. If you make changes to your pull request, please simply add a new commit as that makes it easy for us to review your new changes. If you force push, we'll have to review everything from the beginning. -12. PR should be small, easy to review and should follow standard coding styles. -13. If PR has conflicts because of recently added changes to the same file, resolve issues, test new changes and submit PR again for review. -14. PRs should be atomic. That is, they should address one item (issue or feature) -15. After submitting PR, if you are not replying within 48 hours then in that case we may need to assign issue to other contributors based on priority of the issue. diff --git a/PR_GUIDELINES.md b/PR_GUIDELINES.md new file mode 100644 index 0000000000..4c904c782d --- /dev/null +++ b/PR_GUIDELINES.md @@ -0,0 +1,69 @@ +# Pull Request Guidelines + +:+1::tada: First off, thanks for taking the time to contribute! :tada::+1: + +In order to give everyone a chance to submit a pull request and contribute to the Talawa project, we have put restrictions in place. This section outlines the guidelines that should be imposed upon pull requests in the Talawa project. + +# Table of Contents + + + +- [Pull Requests and Issues](#pull-requests-and-issues) +- [Linting and Formatting](#linting-and-formatting) +- [Testing](#testing) +- [Pull Request Processing](#pull-request-processing) + - [Only submit PRs against our `develop` branch, not the default `main` branch](#only-submit-prs-against-our-develop-branch-not-the-default-main-branch) + + + +## Pull Requests and Issues + +1. Do not start working on any open issue and raise a PR unless the issue is assigned to you. PRs that don't meet these guidelines will be closed. +1. Pull requests must be based on [open issues](https://github.com/PalisadoesFoundation/talawa-admin/issues) available. +1. [Use this method to automatically close the issue when the PR is completed.](https://docs.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue) + +## Linting and Formatting + +All the pull requests must have code that is properly linted and formatted, so that uniformity across the repository can be ensured. + +Before opening a PR, you can run the following scripts to automatically lint and format the code properly: + +``` +npm run lint:fix +npm run format:fix +``` + +Both of these scripts also have a `check` counterpart, which would be used by the GitHub CI to ensure that the code is properly formatted. +You can run the following scripts yourself to ensure that your pull request doesn't fail due to linting and formatting errors: + +``` +npm run lint:check +npm run format:check +``` + +## Testing + +1. All pull requests must have test units. If, for some reason, it is not possible to add tests, please let us know and explain why. In that case, you'll need to tell us what steps you followed to manually test your changes. +1. Please read our [CONTRIBUTING.md](CONTRIBUTING.md) document for details on our testing policy. + +## Pull Request Processing +These are key guidelines for the procedure: + +### Only submit PRs against our `develop` branch, not the default `main` branch + +1. Only submit PRs against our `develop` branch. The default is `main`, so you will have to modify this before submitting your PR for review. PRs made against `main` will be closed. +1. We do not accept draft Pull Requests. They will be closed if submitted. We focus on work that is ready for immediate review. +1. Removing assigned reviewers from your Pull Request will cause it to be closed. The quality of our code is very important to us. Therefore we make experienced maintainers of our code base review your code. Removing these assigned persons is not in the best interest of this goal. +1. If you have not done so already, please read the `Pull Requests and Issues` and `Testing` sections above. +1. Each contributor may only create one pull request at a time. We have this rule in place due to our limited resources - if everyone was allowed to post multiple pull requests, we would not be able to review them properly. It is also better for contributors because you can focus on creating one quality PR - so spend time making sure it is as good as it can be. +1. Upon successful push to the fork, check if all tests are passing; if not, fix the issues and then create a pull request. +1. If the pull request's code quality is not up to par, or it would break the app, it will more likely be closed. So please be careful when creating a PR. +1. Please follow the PR template provided. Ensure the PR title clearly describes the problem it is solving. In the description, include the relevant issue number, snapshots, and videos after changes are added. +1. If you are borrowing a code, please disclose it. It is fine and sometimes even recommended to borrow code, but we need to know about it to assess your work. If we find out that your pull request contains a lot of code copied from elsewhere, we will close the pull request. +1. No Work In Progress. ONLY completed and working pull requests and with respective test units will be accepted. A WIP would fall under rule 4 and be closed immediately. +1. Please do not @mention contributors and mentors. Sometimes it takes time before we can review your pull request or answer your questions, but we'll get to it sooner or later. @mentioning someone just adds to the pile of notifications we get and it won't make us look at your issue faster. +1. Do not force push. If you make changes to your pull request, please simply add a new commit, as that makes it easy for us to review your new changes. If you force push, we'll have to review everything from the beginning. +1. PR should be small, easy to review and should follow standard coding styles. +1. If PR has conflicts because of recently added changes to the same file, resolve issues, test new changes, and submit PR again for review. +1. PRs should be atomic. That is, they should address one item (issue or feature) +1. After submitting PR, if you are not replying within 48 hours, then in that case, we may need to assign the issue to other contributors based on the priority of the issue. diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 435ecf4ada..0000000000 --- a/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,15 +0,0 @@ -- **Please check if the PR fulfills these requirements** - -* [ ] The commit message follows our guidelines -* [ ] Tests for the changes have been added (for bug fixes / features) -* [ ] Docs have been added / updated (for bug fixes / features) - -- **What kind of change does this PR introduce?** (Bug fix, feature, docs update, ...) - -- **What is the current behavior?** (You can also link to an open issue here) - -- **What is the new behavior (if this is a feature change)?** - -- **Does this PR introduce a breaking change?** (What changes might users need to make in their application due to this PR?) - -- **Other information**: diff --git a/README.md b/README.md index 66d98dd25c..21692075fc 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,13 @@ # Talawa Admin +[💬 Join the community on Slack](https://github.com/PalisadoesFoundation/) + +![talawa-logo-lite-200x200](https://github.com/PalisadoesFoundation/talawa-admin/assets/16875803/26291ec5-d3c1-4135-8bc7-80885dff613d) + [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![GitHub stars](https://img.shields.io/github/stars/PalisadoesFoundation/talawa-admin.svg?style=social&label=Star&maxAge=2592000)](https://github.com/PalisadoesFoundation/talawa-admin) [![GitHub forks](https://img.shields.io/github/forks/PalisadoesFoundation/talawa-admin.svg?style=social&label=Fork&maxAge=2592000)](https://github.com/PalisadoesFoundation/talawa-admin) - -[![N|Solid](src/assets/talawa-logo-lite-200x200.png)](https://github.com/PalisadoesFoundation/talawa-admin) +[![codecov](https://codecov.io/gh/PalisadoesFoundation/talawa-admin/branch/develop/graph/badge.svg?token=II0R0RREES)](https://codecov.io/gh/PalisadoesFoundation/talawa-admin) Talawa is a modular open source project to manage group activities of both non-profit organizations and businesses. @@ -18,6 +21,16 @@ Core features include: `talawa` is based on the original `quito` code created by the [Palisadoes Foundation][pfd] as part of its annual Calico Challenge program. Calico provides paid summer internships for Jamaican university students to work on selected open source projects. They are mentored by software professionals and receive stipends based on the completion of predefined milestones. Calico was started in 2015. Visit [The Palisadoes Foundation's website](http://www.palisadoes.org/) for more details on its origin and activities. +# Table of Contents + + + +- [Talawa Components](#talawa-components) +- [Documentation](#documentation) +- [Videos](#videos) + + + # Talawa Components `talawa` has these major software components: @@ -29,44 +42,15 @@ Core features include: # Documentation -- The `talawa` documentation can be found [here](https://palisadoesfoundation.github.io/talawa-docs/). -- Want to contribute? Look at [CONTRIBUTING.md](CONTRIBUTING.md) to get started. -- Visit the [Talawa-Docs GitHub](https://github.com/PalisadoesFoundation/talawa-docs) to see the code. - -# Project Setup - -``` -yarn install -``` - -## Compiles and hot-reloads for development - -``` -yarn serve -``` - -## Compiles and minifies for production - -``` -yarn build -``` - -## Run your end-to-end tests - -``` -yarn test:e2e -``` - -## Lints and fixes files - -``` -yarn lint -``` - -## Customize configuration - -See [Configuration Reference](https://cli.vuejs.org/config/). +1. You can install the software for this repository using the steps in our [INSTALLATION.md](INSTALLATION.md) file. +1. Do you want to contribute to our code base? Look at our [CONTRIBUTING.md](CONTRIBUTING.md) file to get started. There you'll also find links to: + 1. Our code of conduct documentation in the [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) file. + 1. How we handle the processing of new and existing issues in our [ISSUE_GUIDELINES.md](ISSUE_GUIDELINES.md) file. + 1. The methodologies we use to manage our pull requests in our [PR_GUIDELINES.md](PR_GUIDELINES.md) file. +1. The `talawa` documentation can be found at our [docs.talawa.io](https://docs.talawa.io) site. + 1. It is automatically generated from the markdown files stored in our [Talawa-Docs GitHub repository](https://github.com/PalisadoesFoundation/talawa-docs). This makes it easy for you to update our documenation. -## Project setup using docker +# Videos -See [Docker Container](Docker_Container/README.md) +1. Visit our [YouTube Channel playlists](https://www.youtube.com/@PalisadoesOrganization/playlists) for more insights + 1. The "Getting Started - Developers" videos are extremely helpful for new open source contributors. diff --git a/issue-guidelines.md b/issue-guidelines.md deleted file mode 100644 index 5d626c332d..0000000000 --- a/issue-guidelines.md +++ /dev/null @@ -1,12 +0,0 @@ -# Issue Report Guidelines - -:+1::tada: First off, thanks for taking the time to contribute! :tada::+1: - -In order to give everyone a chance to submit a issues reports and contribute to the Talawa API project, we have put restrictions in place. This section outlines the guidelines that should be imposed upon issue reports in the Talawa API project. - -1. Use the [GitHub open issue search](https://github.com/PalisadoesFoundation/talawa-admin/issues) — check if the issue has already been reported. -2. If the issue is already reported and not assigned to anyone, if you are interested to work on the issue then ask mentors to assign issign to you in #talawa-api slack channel. -3. Check if the issue has been fixed — try to reproduce it using the latest master or development branch in the repository. -4. For newly found unfixed issues or features, start discussing it in #gsoc-newissues channel with mentors. Please do not derail or troll issues. Keep the discussion on topic and respect the opinions of others. -5. After mentor approval you can create a new issue by following [issue template](https://github.com/PalisadoesFoundation/talawa-admin/blob/master/templates/issue-template.md) available here. -6. Feature requests are welcome. But take a moment to find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the mentors of the merits of this feature. Please provide as much detail and context as possible. diff --git a/jest-preview.config.ts b/jest-preview.config.ts new file mode 100644 index 0000000000..0bcc13d4c7 --- /dev/null +++ b/jest-preview.config.ts @@ -0,0 +1,5 @@ +export default { + moduleNameMapper: { + '^@mui/(.*)$': '/node_modules/@mui/$1', + }, +}; diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000000..34f219ba06 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,67 @@ +export default { + roots: ['/src'], + collectCoverageFrom: ['src/**/*.{ts,tsx}', '!src/index.tsx'], + setupFiles: ['react-app-polyfill/jsdom'], + setupFilesAfterEnv: ['/src/setupTests.ts'], + testMatch: [ + '/src/**/__tests__/**/*.{js,jsx,ts,tsx}', + '/src/**/*.{spec,test}.{js,jsx,ts,tsx}', + ], + testEnvironment: 'jsdom', + transform: { + '^.+\\.(js|jsx|mjs|cjs|ts|tsx)$': + 'react-scripts/config/jest/babelTransform.js', + '^.+\\.(css|scss|sass|less)$': 'jest-preview/transforms/css', + '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': + 'jest-preview/transforms/file', + }, + transformIgnorePatterns: [ + '[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$', + ], + modulePaths: [ + '/Users/prathamesh/Desktop/Open-Source/palisadoes/talawa-admin/src', + '/src', + ], + moduleNameMapper: { + '^react-native$': 'react-native-web', + '^@mui/(.*)$': '/node_modules/@mui/$1', + '^@dicebear/core$': '/scripts/__mocks__/@dicebear/core.ts', + '^@dicebear/collection$': + '/scripts/__mocks__/@dicebear/collection.ts', + }, + moduleFileExtensions: [ + 'web.js', + 'js', + 'web.ts', + 'ts', + 'web.tsx', + 'tsx', + 'json', + 'web.jsx', + 'jsx', + 'node', + ], + watchPlugins: [ + 'jest-watch-typeahead/filename', + 'jest-watch-typeahead/testname', + ], + resetMocks: false, + coveragePathIgnorePatterns: [ + 'src/state/index.ts', + 'src/components/plugins/index.ts', + 'src/components/AddOn/support/services/Render.helper.ts', + 'src/components/SecuredRoute/SecuredRoute.tsx', + 'src/reportWebVitals.ts', + ], + coverageThreshold: { + global: { + lines: 20, + statements: 20, + }, + }, + testPathIgnorePatterns: [ + '/node_modules/', + '/build/', + '/public/', + ], +}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000..97b7d7b9c2 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,49612 @@ +{ + "name": "talawa-admin", + "version": "3.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "talawa-admin", + "version": "3.0.0", + "dependencies": { + "@apollo/client": "^3.4.0-beta.19", + "@apollo/link-error": "^2.0.0-beta.3", + "@apollo/react-testing": "^4.0.0", + "@dicebear/collection": "^8.0.1", + "@dicebear/core": "^8.0.1", + "@emotion/react": "^11.11.4", + "@emotion/styled": "^11.11.5", + "@mui/icons-material": "^5.16.1", + "@mui/material": "^5.16.4", + "@mui/private-theming": "^5.15.12", + "@mui/system": "^5.14.12", + "@mui/x-charts": "^7.8.0", + "@mui/x-data-grid": "^7.11.0", + "@mui/x-date-pickers": "^7.6.1", + "@pdfme/generator": "^1.2.6", + "bootstrap": "^5.3.3", + "customize-cra": "^1.0.0", + "dayjs": "^1.11.11", + "flag-icons": "^6.6.6", + "graphql": "^16.9.0", + "graphql-tag": "^2.12.6", + "graphql-ws": "^5.16.0", + "history": "^5.3.0", + "i18next": "^21.8.14", + "i18next-browser-languagedetector": "^8.0.0", + "i18next-http-backend": "^2.5.2", + "inquirer": "^8.0.0", + "jest-watch-typeahead": "^2.2.2", + "js-cookie": "^3.0.1", + "markdown-toc": "^1.2.0", + "prettier": "^3.3.2", + "react": "^17.0.2", + "react-app-rewired": "^2.2.1", + "react-beautiful-dnd": "^13.1.1", + "react-bootstrap": "^2.7.4", + "react-datepicker": "^7.3.0", + "react-dom": "^17.0.2", + "react-google-recaptcha": "^3.1.0", + "react-i18next": "^11.18.1", + "react-icons": "^5.2.1", + "react-infinite-scroll-component": "^6.1.0", + "react-multi-carousel": "^2.8.5", + "react-redux": "^7.2.5", + "react-router-dom": "^6.25.1", + "react-scripts": "5.0.1", + "react-toastify": "^9.0.3", + "react-tooltip": "^5.27.1", + "redux": "^4.1.1", + "redux-thunk": "^2.3.0", + "sanitize-html": "^2.13.0", + "typedoc-plugin-markdown": "^4.2.1", + "typescript": "^4.3.5", + "web-vitals": "^4.2.2" + }, + "devDependencies": { + "@babel/plugin-proposal-private-property-in-object": "^7.21.11", + "@testing-library/jest-dom": "^6.4.5", + "@testing-library/react": "^11.1.0", + "@testing-library/user-event": "^12.1.10", + "@types/inquirer": "^9.0.7", + "@types/jest": "^29.5.12", + "@types/js-cookie": "^3.0.6", + "@types/node": "^20.12.12", + "@types/node-fetch": "^2.6.10", + "@types/react": "^17.0.14", + "@types/react-beautiful-dnd": "^13.1.8", + "@types/react-bootstrap": "^0.32.32", + "@types/react-datepicker": "^4.1.4", + "@types/react-dom": "^17.0.9", + "@types/react-google-recaptcha": "^2.1.5", + "@types/react-router-dom": "^5.1.8", + "@types/sanitize-html": "^2.11.0", + "@typescript-eslint/eslint-plugin": "^5.9.0", + "@typescript-eslint/parser": "^5.9.0", + "cross-env": "^7.0.3", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-jest": "^25.3.4", + "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-react": "^7.34.1", + "eslint-plugin-tsdoc": "^0.2.17", + "husky": "^8.0.3", + "identity-obj-proxy": "^3.0.0", + "jest": "^29.7.0", + "jest-localstorage-mock": "^2.4.19", + "jest-location-mock": "^2.0.0", + "jest-preview": "^0.3.1", + "lint-staged": "^15.2.7", + "postcss-modules": "^6.0.0", + "sass": "^1.77.4", + "tsx": "^4.16.2" + }, + "engines": { + "node": ">=20.x" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.3.tgz", + "integrity": "sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==", + "dev": true + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@apideck/better-ajv-errors": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz", + "integrity": "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==", + "dependencies": { + "json-schema": "^0.4.0", + "jsonpointer": "^5.0.0", + "leven": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "ajv": ">=8" + } + }, + "node_modules/@apollo/client": { + "version": "3.7.17", + "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.7.17.tgz", + "integrity": "sha512-0EErSHEtKPNl5wgWikHJbKFAzJ/k11O0WO2QyqZSHpdxdAnw7UWHY4YiLbHCFG7lhrD+NTQ3Z/H9Jn4rcikoJA==", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "@wry/context": "^0.7.0", + "@wry/equality": "^0.5.0", + "@wry/trie": "^0.4.0", + "graphql-tag": "^2.12.6", + "hoist-non-react-statics": "^3.3.2", + "optimism": "^0.16.2", + "prop-types": "^15.7.2", + "response-iterator": "^0.2.6", + "symbol-observable": "^4.0.0", + "ts-invariant": "^0.10.3", + "tslib": "^2.3.0", + "zen-observable-ts": "^1.2.5" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0", + "graphql-ws": "^5.5.5", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", + "subscriptions-transport-ws": "^0.9.0 || ^0.11.0" + }, + "peerDependenciesMeta": { + "graphql-ws": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "subscriptions-transport-ws": { + "optional": true + } + } + }, + "node_modules/@apollo/link-error": { + "version": "2.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@apollo/link-error/-/link-error-2.0.0-beta.3.tgz", + "integrity": "sha512-blNBBi9+4SEfb4Bhn8cYqGFhb0C7MjqLiRwNdUqwGefl1w+G8Ze8pCLHAyPxXLcslirtht9LY0i6ZOpCzSXHCg==", + "dependencies": { + "@apollo/client": "^3.0.0-beta.23", + "tslib": "^1.9.3" + } + }, + "node_modules/@apollo/link-error/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@apollo/react-testing": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@apollo/react-testing/-/react-testing-4.0.0.tgz", + "integrity": "sha512-P7Z/flUHpRRZYc3FkIqxZH9XD3FuP2Sgks1IXqGq2Zb7qI0aaTfVeRsLYmZNUcFOh2pTHxs0NXgPnH1VfYOpig==", + "dependencies": { + "@apollo/client": "latest" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz", + "integrity": "sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/eslint-parser": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.22.9.tgz", + "integrity": "sha512-xdMkt39/nviO/4vpVdrEYPwXCsYIXSSAr6mC7WQsNIlGnuxKyKE7GZjalcnbSWiC4OXGNNN3UQPeHfjSC6sTDA==", + "dependencies": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.11.0", + "eslint": "^7.5.0 || ^8.0.0" + } + }, + "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@babel/eslint-parser/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", + "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "dependencies": { + "@babel/types": "^7.22.15" + }, + "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==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.23.10", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.10.tgz", + "integrity": "sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.1.tgz", + "integrity": "sha512-kX4oXixDxG197yhX+J3Wp+NpL2wuCFjWQAr6yX2jtCnflK9ulMI51ULFGIrWiX1jGfvAxdHp+XQCcP2bZGPs9A==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "dependencies": { + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "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==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", + "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "dependencies": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz", + "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "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.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.0.tgz", + "integrity": "sha512-CzdIU9jdP0dg7HdyB+bHvDJGagUv+qtzZt5rYCWwW6tITNqV9odjp6Qu41gkG0ca5UfdDUWrKkiAnHHdGRnOrA==", + "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz", + "integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz", + "integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.7.tgz", + "integrity": "sha512-LlRT7HgaifEpQA1ZgLVOIJZZFVPWN5iReq/7/JixwBtwcoeVGDBD53ZV28rrsLYOZs1Y/EHhA8N/Z6aazHR8cw==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.22.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.22.7.tgz", + "integrity": "sha512-omXqPF7Onq4Bb7wHxXjM3jSMSJvUUbvDvmmds7KI5n9Cq6Ln5I05I1W2nRlRof1rGdiUxJrxwe285WF96XlBXQ==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/plugin-syntax-decorators": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", + "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz", + "integrity": "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.22.5.tgz", + "integrity": "sha512-avpUOBS7IU6al8MmF1XpAyj9QYeLPuSDJI5D4pVMSMdL7xQokKqJPYQC67RCT0aCTashUXPiGwMJ0DEXXCEmMA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.22.5.tgz", + "integrity": "sha512-9RdCl0i+q0QExayk2nOS7853w08yLucnnPML6EN9S8fgMPVtdLDCdx/cOQ/i44Lb9UeQX9A35yaqBBOMMZxPxQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz", + "integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz", + "integrity": "sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", + "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", + "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", + "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.9.tgz", + "integrity": "sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", + "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", + "dependencies": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", + "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz", + "integrity": "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz", + "integrity": "sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.4.tgz", + "integrity": "sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.8.tgz", + "integrity": "sha512-yAYslGsY1bX6Knmg46RjiCiNSwJKv2IUC8qOdYKqMMr0491SXFhcHqOdRDeCRohOOIzwN/90C6mQ9qAKgrP7dg==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", + "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", + "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz", + "integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz", + "integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.4.tgz", + "integrity": "sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", + "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz", + "integrity": "sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.22.5.tgz", + "integrity": "sha512-tujNbZdxdG0/54g/oua8ISToaXTFBf8EnSb5PgQSciIXWOWKX3S4+JR7ZE9ol8FZwf9kxitzkGQ+QWeov/mCiA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-flow": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.6.tgz", + "integrity": "sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz", + "integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.4.tgz", + "integrity": "sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", + "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.4.tgz", + "integrity": "sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz", + "integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", + "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", + "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.9.tgz", + "integrity": "sha512-KDlPRM6sLo4o1FkiSlXoAa8edLXFsKKIda779fbLrvmeuc3itnjCtaO6RrtoaANsIJANj+Vk1zqbZIMhkCAHVw==", + "dependencies": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", + "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", + "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz", + "integrity": "sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.4.tgz", + "integrity": "sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz", + "integrity": "sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==", + "dependencies": { + "@babel/compat-data": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", + "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.4.tgz", + "integrity": "sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz", + "integrity": "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", + "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz", + "integrity": "sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz", + "integrity": "sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", + "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.22.5.tgz", + "integrity": "sha512-BF5SXoO+nX3h5OhlN78XbbDrBOffv+AxPP2ENaJOVqjWCgBDeOY3WcaUcddutGSfoap+5NEQ/q/4I3WZIvgkXA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.22.5.tgz", + "integrity": "sha512-PVk3WPYudRF5z4GKMEYUrLjPl38fJSKNaEOkFuoprioowGuWN6w2RKznuFNSlJx7pzzXXStPUnNSOEO0jL5EVw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.5.tgz", + "integrity": "sha512-rog5gZaVbUip5iWDMTYbVM15XQq+RkUKhET/IHR6oizR+JEoN6CAfTTuHcK4vwUyzca30qqHqEpzBOnaRMWYMA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz", + "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.22.5.tgz", + "integrity": "sha512-gP4k85wx09q+brArVinTXhWiyzLl9UpmGva0+mWyKxk6JZequ05x3eUcIUE+FyttPKJFRRVtAvQaJ6YF9h1ZpA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", + "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", + "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.9.tgz", + "integrity": "sha512-9KjBH61AGJetCPYp/IEyLEp47SyybZb0nDRpBvmtEkm+rUIwxdlKpyNHI1TmsGkeuLclJdleQHRZ8XLBnnh8CQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "babel-plugin-polyfill-corejs2": "^0.4.4", + "babel-plugin-polyfill-corejs3": "^0.8.2", + "babel-plugin-polyfill-regenerator": "^0.5.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", + "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", + "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", + "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", + "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", + "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.23.6.tgz", + "integrity": "sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.23.6", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-typescript": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", + "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz", + "integrity": "sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", + "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz", + "integrity": "sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.9.tgz", + "integrity": "sha512-3kBGTNBBk9DQiPoXYS0g0BYlwTQYUTifqgKTjxUwEUkduRT2QOa0FPGBJ+NROQhGyYO5BuTJwGvBnqKDykac6A==", + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.23.3", + "@babel/plugin-syntax-import-attributes": "^7.23.3", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.23.3", + "@babel/plugin-transform-async-generator-functions": "^7.23.9", + "@babel/plugin-transform-async-to-generator": "^7.23.3", + "@babel/plugin-transform-block-scoped-functions": "^7.23.3", + "@babel/plugin-transform-block-scoping": "^7.23.4", + "@babel/plugin-transform-class-properties": "^7.23.3", + "@babel/plugin-transform-class-static-block": "^7.23.4", + "@babel/plugin-transform-classes": "^7.23.8", + "@babel/plugin-transform-computed-properties": "^7.23.3", + "@babel/plugin-transform-destructuring": "^7.23.3", + "@babel/plugin-transform-dotall-regex": "^7.23.3", + "@babel/plugin-transform-duplicate-keys": "^7.23.3", + "@babel/plugin-transform-dynamic-import": "^7.23.4", + "@babel/plugin-transform-exponentiation-operator": "^7.23.3", + "@babel/plugin-transform-export-namespace-from": "^7.23.4", + "@babel/plugin-transform-for-of": "^7.23.6", + "@babel/plugin-transform-function-name": "^7.23.3", + "@babel/plugin-transform-json-strings": "^7.23.4", + "@babel/plugin-transform-literals": "^7.23.3", + "@babel/plugin-transform-logical-assignment-operators": "^7.23.4", + "@babel/plugin-transform-member-expression-literals": "^7.23.3", + "@babel/plugin-transform-modules-amd": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.9", + "@babel/plugin-transform-modules-umd": "^7.23.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.23.3", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", + "@babel/plugin-transform-numeric-separator": "^7.23.4", + "@babel/plugin-transform-object-rest-spread": "^7.23.4", + "@babel/plugin-transform-object-super": "^7.23.3", + "@babel/plugin-transform-optional-catch-binding": "^7.23.4", + "@babel/plugin-transform-optional-chaining": "^7.23.4", + "@babel/plugin-transform-parameters": "^7.23.3", + "@babel/plugin-transform-private-methods": "^7.23.3", + "@babel/plugin-transform-private-property-in-object": "^7.23.4", + "@babel/plugin-transform-property-literals": "^7.23.3", + "@babel/plugin-transform-regenerator": "^7.23.3", + "@babel/plugin-transform-reserved-words": "^7.23.3", + "@babel/plugin-transform-shorthand-properties": "^7.23.3", + "@babel/plugin-transform-spread": "^7.23.3", + "@babel/plugin-transform-sticky-regex": "^7.23.3", + "@babel/plugin-transform-template-literals": "^7.23.3", + "@babel/plugin-transform-typeof-symbol": "^7.23.3", + "@babel/plugin-transform-unicode-escapes": "^7.23.3", + "@babel/plugin-transform-unicode-property-regex": "^7.23.3", + "@babel/plugin-transform-unicode-regex": "^7.23.3", + "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.8", + "babel-plugin-polyfill-corejs3": "^0.9.0", + "babel-plugin-polyfill-regenerator": "^0.5.5", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", + "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.9.0.tgz", + "integrity": "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.5.0", + "core-js-compat": "^3.34.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.22.5.tgz", + "integrity": "sha512-M+Is3WikOpEJHgR385HbuCITPTaPRaNkibTEa9oiofmJvIsrceb4yp9RL9Kb+TE8LznmeyZqpP+Lopwcx59xPQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "@babel/plugin-transform-react-display-name": "^7.22.5", + "@babel/plugin-transform-react-jsx": "^7.22.5", + "@babel/plugin-transform-react-jsx-development": "^7.22.5", + "@babel/plugin-transform-react-pure-annotations": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.23.3.tgz", + "integrity": "sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", + "@babel/plugin-syntax-jsx": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-typescript": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@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==" + }, + "node_modules/@babel/runtime": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", + "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.22.6.tgz", + "integrity": "sha512-M+37LLIRBTEVjktoJjbw4KVhupF0U/3PYUCbBwgAd9k17hoKhRu1n935QiG7Tuxv0LJOMrb2vuKEeYUlv0iyiw==", + "dev": true, + "dependencies": { + "core-js-pure": "^3.30.2", + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime/node_modules/regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" + }, + "node_modules/@babel/template": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.2.tgz", + "integrity": "sha512-s4/r+a7xTnny2O6FcZzqgT6nE4/GHEdcqj4qAeglbUOh0TeglEfmNJFAd/OLoVtGd6ZhAO8GCVvCNUO5t/VJVQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.2", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", + "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "license": "MIT" + }, + "node_modules/@csstools/normalize.css": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-12.0.0.tgz", + "integrity": "sha512-M0qqxAcwCsIVfpFQSlGN5XjXWu8l5JDZN+fPt1LeW5SZexQTgnaEvgXAY+CeygRw0EeppWHi12JxESWiWrB0Sg==" + }, + "node_modules/@csstools/postcss-cascade-layers": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", + "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", + "dependencies": { + "@csstools/selector-specificity": "^2.0.2", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-color-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz", + "integrity": "sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-font-format-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz", + "integrity": "sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-hwb-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz", + "integrity": "sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-ic-unit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz", + "integrity": "sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz", + "integrity": "sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==", + "dependencies": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-nested-calc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-1.0.0.tgz", + "integrity": "sha512-JCsQsw1wjYwv1bJmgjKSoZNvf7R6+wuHDAbi5f/7MbFhl2d/+v+TvBTU4BJH3G1X1H87dHl0mh6TfYogbT/dJQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-normalize-display-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz", + "integrity": "sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-oklab-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz", + "integrity": "sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-progressive-custom-properties": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", + "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/@csstools/postcss-stepped-value-functions": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz", + "integrity": "sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-text-decoration-shorthand": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-1.0.0.tgz", + "integrity": "sha512-c1XwKJ2eMIWrzQenN0XbcfzckOLLJiczqy+YvfGmzoVXd7pT9FfObiSEfzs84bpE/VqfpEuAZ9tCRbZkZxxbdw==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-trigonometric-functions": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz", + "integrity": "sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-unset-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz", + "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==", + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/selector-specificity": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz", + "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==", + "engines": { + "node": "^14 || ^16 || >=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss-selector-parser": "^6.0.10" + } + }, + "node_modules/@dicebear/adventurer": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/adventurer/-/adventurer-8.0.1.tgz", + "integrity": "sha512-dlEycOH+yETbNo3EtswFJCnG02OEgpyPpOFmSgUuRhcRKsqbMlcsiYV4wKeRvq6VvudJXp8UiHwWszLjCHTvKA==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/adventurer-neutral": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/adventurer-neutral/-/adventurer-neutral-8.0.1.tgz", + "integrity": "sha512-NgSz01T/K6MJn93Lk8rKPGKTx6cJe4/lNKMKjRM+4mez8S56WNdGDGUn/QY5GL3P1p01QAOMFF3hygJk3WAr3g==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/avataaars": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/avataaars/-/avataaars-8.0.1.tgz", + "integrity": "sha512-TYXqP9mq3yHOdLlJr8saXnvxj14eY2YAmoVVbT15Rp5+kPzGDyfblNsM838sP5K6JyCNeojZsGE/sPJKk/G+mA==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/avataaars-neutral": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/avataaars-neutral/-/avataaars-neutral-8.0.1.tgz", + "integrity": "sha512-vMV1Htaqpnz+qAVyn2tJWbRQIa6mpO/bu7dD0dumuIb45+LIpNwdUuCvkIQw2qf5ODhn1WAfYX3HEJaxRZc4lA==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/big-ears": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/big-ears/-/big-ears-8.0.1.tgz", + "integrity": "sha512-lnPRFbXsHv2EXJR2OLqJdoUIrSVUpf1z4GkCOfAi01sYNYVpfnzg3kNF77QUhkXUhaONF7d4Wz8rUduBHRtjaA==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/big-ears-neutral": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/big-ears-neutral/-/big-ears-neutral-8.0.1.tgz", + "integrity": "sha512-2FPvNpLI/ald3P8iWhX7SR986B8/DQlvrTNK/v+V0HRJvG1t6/7f9qfUL7OLf6plL7EgSUmKfMKacdiR5skZkA==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/big-smile": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/big-smile/-/big-smile-8.0.1.tgz", + "integrity": "sha512-uh7FP0RgX8Qtr5zpeKUSNq028IQ3srF5LHJfQGjf4wA8R+ln/Sq0gPRJk6qMCCvPFV42b7A6f7rO7mHGnQ+qDA==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/bottts": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/bottts/-/bottts-8.0.1.tgz", + "integrity": "sha512-WmaGZnKAT90EP/pzfUox22RshCk3GLB/p+6SsjD0ZIBNjcMXhaJroSoGVcHmPgQVzZBDIdW9C0qDKhkCNVVizg==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/bottts-neutral": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/bottts-neutral/-/bottts-neutral-8.0.1.tgz", + "integrity": "sha512-krbD3U+UvzlY+kfQDpg9Hql1xJmmu3y9ensiU+XZXiuNw/ZavgGqpJtzpbYeF3J5GsggQlbBh/ZAK9AIKz7S3Q==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/collection": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/collection/-/collection-8.0.1.tgz", + "integrity": "sha512-RlWvOOXTxqP1llNzWhrnm6wCMKFAku/Ty0YJNv+4LYA1YIDpyLNN2PwxxCuj7hU244qUwQcVPQPPPr0XQ+rA/g==", + "dependencies": { + "@dicebear/adventurer": "8.0.1", + "@dicebear/adventurer-neutral": "8.0.1", + "@dicebear/avataaars": "8.0.1", + "@dicebear/avataaars-neutral": "8.0.1", + "@dicebear/big-ears": "8.0.1", + "@dicebear/big-ears-neutral": "8.0.1", + "@dicebear/big-smile": "8.0.1", + "@dicebear/bottts": "8.0.1", + "@dicebear/bottts-neutral": "8.0.1", + "@dicebear/croodles": "8.0.1", + "@dicebear/croodles-neutral": "8.0.1", + "@dicebear/fun-emoji": "8.0.1", + "@dicebear/icons": "8.0.1", + "@dicebear/identicon": "8.0.1", + "@dicebear/initials": "8.0.1", + "@dicebear/lorelei": "8.0.1", + "@dicebear/lorelei-neutral": "8.0.1", + "@dicebear/micah": "8.0.1", + "@dicebear/miniavs": "8.0.1", + "@dicebear/notionists": "8.0.1", + "@dicebear/notionists-neutral": "8.0.1", + "@dicebear/open-peeps": "8.0.1", + "@dicebear/personas": "8.0.1", + "@dicebear/pixel-art": "8.0.1", + "@dicebear/pixel-art-neutral": "8.0.1", + "@dicebear/rings": "8.0.1", + "@dicebear/shapes": "8.0.1", + "@dicebear/thumbs": "8.0.1" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/converter": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/converter/-/converter-8.0.1.tgz", + "integrity": "sha512-65L04fN4V07WcUnwQuDYDH+zrP8WA6/UeIuqqH/Pv7VWoJtIk9qHlaA+XGpPr4qgRtkmY7uXVkrED/RMlqvUDA==", + "dependencies": { + "@types/json-schema": "^7.0.11", + "tmp-promise": "^3.0.3" + }, + "engines": { + "node": ">=16.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 + } + } + }, + "node_modules/@dicebear/core": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/core/-/core-8.0.1.tgz", + "integrity": "sha512-HWqvQRpVjkboQXinCOjU3poZIMd5p+32wPvc9N5fYiXe3KQLhJNw5T5XiRttDUm3XpoTvhQ4DVTPDsXT8CqrTg==", + "dependencies": { + "@dicebear/converter": "8.0.1", + "@types/json-schema": "^7.0.11" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@dicebear/croodles": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/croodles/-/croodles-8.0.1.tgz", + "integrity": "sha512-4si6gm61hEI8uDk+7OhSX+0qSPfotYx1dbdBphgGgiP9KTOgipnXzNtz8YnGzNf+V89nV4twHa6Bl6Wna4kFYA==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/croodles-neutral": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/croodles-neutral/-/croodles-neutral-8.0.1.tgz", + "integrity": "sha512-DlR1wxzacRc3GhkMRg4MJ4CBfci/Z96SUl3YpvhHQ4ZtPldaQmdxs3jzOlnG1cuNRkqmiB1D66EXj5146V5WMA==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/fun-emoji": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/fun-emoji/-/fun-emoji-8.0.1.tgz", + "integrity": "sha512-s2zXyZ7Rp3E2OHxAghhKIYmTtQ64D1VU+/p0VNaIQTPnyfxgpdrKlBMAlp4fXHyirhtAWCHSWgXcU9UFvlmr+w==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/icons": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/icons/-/icons-8.0.1.tgz", + "integrity": "sha512-uInO34VW1etgMsbarXIeYULTk+dlj0L9vW7nUinWqwwEbimgXT4iqzNSjQyogmQ3wmaahI1zNwrGUkfkQojouw==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/identicon": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/identicon/-/identicon-8.0.1.tgz", + "integrity": "sha512-mIHBuUlTs1RNZg+9k4NIjYXYjZBh08ksK/7Pmb+5twsoIPuAPjZ+FbQsfc27Wga/IuJfgf9mYBq6Sxc8/LQxjg==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/initials": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/initials/-/initials-8.0.1.tgz", + "integrity": "sha512-ctO1f92XAms72qkhiKI/vvS/E6mco1RiTEACPJGv6hDPfdjR1vxpkzFpo3jm3RohfwOPCN5fH2l3BSinnlbzzw==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/lorelei": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/lorelei/-/lorelei-8.0.1.tgz", + "integrity": "sha512-AY9XDeV7pIojDziiT/9flPWvH/5dswlVvezHQljmLa1H6EIQAIRWj9INeDaS2u2hRTFQKVeYQ1kuP3Omb+t26A==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/lorelei-neutral": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/lorelei-neutral/-/lorelei-neutral-8.0.1.tgz", + "integrity": "sha512-vC5M7jg6UByJyFjBitLB3xKr435FdH8BHD8oVzf9A2MXi/ovQ0bEak9MnxVcrxUufJx7bsgS/XCRYNLUwaQKyw==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/micah": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/micah/-/micah-8.0.1.tgz", + "integrity": "sha512-B7+YCX62CqnjLlJNY6+NXy+HJlyGMzCbrnE38bGdmnH7PZ1IrEnmJny41AcopKziE02h65kdwCZFXy/v7piT4g==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/miniavs": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/miniavs/-/miniavs-8.0.1.tgz", + "integrity": "sha512-mzNAa2cIvsyeRuSnWoQ6l23yiw4BhmzrwdmfJZuDLloh/UNJjyiiCItYSTBmhtxcJrWX8YQTd/2hPdXjsdceTA==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/notionists": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/notionists/-/notionists-8.0.1.tgz", + "integrity": "sha512-wOZPSj7lKIJkxiJHysGUVehPmaisWV9dUNhs4jDApiit3u6cbspDEOXvlAn/68cpGP8LfjsdyCp8yhZ9Wvk15Q==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/notionists-neutral": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/notionists-neutral/-/notionists-neutral-8.0.1.tgz", + "integrity": "sha512-j70iiLZPpLw9JfyziRC8jUaVnbz2NPTZFMd+O08ba3FcTsG0H5+bYimTWL+6fxZ/psN1S3NS/onVvgPkvBWTjg==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/open-peeps": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/open-peeps/-/open-peeps-8.0.1.tgz", + "integrity": "sha512-NQbXmnPjyz3YZOAIEzQY6OFXg3sCIIDZgQZjl3qzTqsmUtZVMRnX8Sk53ig1SIM1kxIAyJ908wplwIYV16zxsw==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/personas": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/personas/-/personas-8.0.1.tgz", + "integrity": "sha512-qxivUbnx4xvE1PvqCg6pBQadVDJVjXaXnxtIUxIRJyDeYIJUxkeBr2A5JOIiNLdypqXoYwhURy5r3NCmesaAWg==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/pixel-art": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/pixel-art/-/pixel-art-8.0.1.tgz", + "integrity": "sha512-WMRKdxP8/PL2UGiLAP7CdgTNaIRpFyLdr+u6RyXAUmWiI25ltnZQjctzCfUrO/Nxywc6L6lBkApZtTaP+X+UHg==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/pixel-art-neutral": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/pixel-art-neutral/-/pixel-art-neutral-8.0.1.tgz", + "integrity": "sha512-jrbwMNjLk8hlOm+hMTT43z2DqXEFtv6/8hhms7VZE9FjcB1GrQy8j6tSClTq/ktkZlWofEGfvD8BrG5HsbKvaw==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/rings": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/rings/-/rings-8.0.1.tgz", + "integrity": "sha512-RcSXPJDdDiyAscUhJMI6pgOgk4or0nzjKndur44U6I+6s0qS3c74zfT//whLUnDnSO2ZTaUGAjQ5gGJtzp5fqQ==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/shapes": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/shapes/-/shapes-8.0.1.tgz", + "integrity": "sha512-Duhe3bcKmcYt7GcUsNP4/OIbcHzgb4L7rfuMpUgqjXKATLYq1Wizsw9/y9wrwII8h7wIMxG6RDSndNbd7ISTtA==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@dicebear/thumbs": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/thumbs/-/thumbs-8.0.1.tgz", + "integrity": "sha512-cK3UeVVWtiGbStpYeKJrCw3Wy+LGNS5sFja2O3ogc/qpjiL7WFX7kYJXOE2neqOUxVItDxg7dfGatxFrsgUTYA==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^8.0.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", + "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/serialize": "^1.1.2", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "dependencies": { + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", + "integrity": "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==", + "dependencies": { + "@emotion/memoize": "^0.8.1" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "node_modules/@emotion/react": { + "version": "11.11.4", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.4.tgz", + "integrity": "sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/cache": "^11.11.0", + "@emotion/serialize": "^1.1.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.4.tgz", + "integrity": "sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ==", + "dependencies": { + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/unitless": "^0.8.1", + "@emotion/utils": "^1.2.1", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + }, + "node_modules/@emotion/styled": { + "version": "11.11.5", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.5.tgz", + "integrity": "sha512-/ZjjnaNKvuMPxcIiUkf/9SHoG4Q196DRl1w82hQ3WCsjo1IUR8uaGWrC6a87CrYAW0Kb/pK7hk8BnLgLRi9KoQ==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/is-prop-valid": "^1.2.2", + "@emotion/serialize": "^1.1.4", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", + "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "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" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "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" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", + "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", + "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", + "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" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "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==", + "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/@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==" + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "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==" + }, + "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==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", + "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "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/@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/@floating-ui/react": { + "version": "0.26.19", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.19.tgz", + "integrity": "sha512-Jk6zITdjjIvjO/VdQFvpRaD3qPwOHH6AoDHxjhpy+oK4KFgaSP871HYWUAPdnLmx1gQ+w/pB312co3tVml+BXA==", + "dependencies": { + "@floating-ui/react-dom": "^2.1.1", + "@floating-ui/utils": "^0.2.4", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz", + "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.4.tgz", + "integrity": "sha512-dWO2pw8hhi+WrXq1YJy2yCuWoL20PddgGaqTgVe4cOS9Q6qklXCiA1tJEqX6BEwRNSCP84/afac9hd4MS+zEUA==" + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "optional": true, + "peer": true + }, + "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.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + }, + "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==", + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "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==", + "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": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/console/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/console/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/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==", + "license": "MIT", + "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" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/core/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "MIT", + "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/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/@jest/core/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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/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==", + "license": "MIT", + "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" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/@jest/core/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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/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==", + "license": "MIT", + "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" + } + }, + "node_modules/@jest/core/node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/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==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/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==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@jest/core/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/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==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/@jest/core/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==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/environment/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/environment/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/environment/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "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/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils/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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/fake-timers/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "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/fake-timers/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==", + "license": "MIT", + "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" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/globals/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "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": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "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==", + "license": "MIT", + "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/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==", + "license": "MIT" + }, + "node_modules/@jest/reporters/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==", + "license": "BSD-3-Clause", + "dependencies": { + "@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" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@jest/reporters/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==", + "license": "MIT", + "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" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/@jest/reporters/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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters/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==", + "license": "MIT", + "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" + } + }, + "node_modules/@jest/reporters/node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/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==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/test-result/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "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/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/test-sequencer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "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/test-sequencer/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==", + "license": "MIT", + "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" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/@jest/test-sequencer/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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer/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==", + "license": "MIT", + "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" + } + }, + "node_modules/@jest/test-sequencer/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==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer/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==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "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==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" + }, + "node_modules/@microsoft/tsdoc": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz", + "integrity": "sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==", + "dev": true + }, + "node_modules/@microsoft/tsdoc-config": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz", + "integrity": "sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==", + "dev": true, + "dependencies": { + "@microsoft/tsdoc": "0.14.2", + "ajv": "~6.12.6", + "jju": "~1.4.0", + "resolve": "~1.19.0" + } + }, + "node_modules/@microsoft/tsdoc-config/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@microsoft/tsdoc-config/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/@microsoft/tsdoc-config/node_modules/resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "dependencies": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "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" + }, + "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" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/base/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.4.tgz", + "integrity": "sha512-rNdHXhclwjEZnK+//3SR43YRx0VtjdHnUFhMSGYmAMJve+KiwEja/41EYh8V3pZKqF2geKyfcFUenTfDTYUR4w==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/icons-material": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.16.1.tgz", + "integrity": "sha512-ogQPweYba4+5XZykilwxn2/oS78uwoQ0BVBpOhhCJo0ooZsqTTsalhzP2qD/RdGqMQ8xyXPz1sYM2djTruVVVA==", + "dependencies": { + "@babel/runtime": "^7.23.9" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/material": "^5.0.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.4.tgz", + "integrity": "sha512-dBnh3/zRYgEVIS3OE4oTbujse3gifA0qLMmuUk13ywsDCbngJsdgwW5LuYeiT5pfA8PGPGSqM7mxNytYXgiMCw==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/core-downloads-tracker": "^5.16.4", + "@mui/system": "^5.16.4", + "@mui/types": "^7.2.15", + "@mui/utils": "^5.16.4", + "@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" + }, + "engines": { + "node": ">=12.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", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@mui/private-theming": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.4.tgz", + "integrity": "sha512-ZsAm8cq31SJ37SVWLRlu02v9SRthxnfQofaiv14L5Bht51B0dz6yQEoVU/V8UduZDCCIrWkBHuReVfKhE/UuXA==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/utils": "^5.16.4", + "prop-types": "^15.8.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/styled-engine": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.4.tgz", + "integrity": "sha512-0+mnkf+UiAmTVB8PZFqOhqf729Yh0Cxq29/5cA3VAyDVTRIUUQ8FXQhiAhUIbijFmM72rY80ahFPXIm4WDbzcA==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@emotion/cache": "^11.11.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.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" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.4.tgz", + "integrity": "sha512-ET1Ujl2/8hbsD611/mqUuNArMCGv/fIWO/f8B3ZqF5iyPHM2aS74vhTNyjytncc4i6dYwGxNk+tLa7GwjNS0/w==", + "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" + }, + "engines": { + "node": ">=12.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", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/system/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@mui/types": { + "version": "7.2.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" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.4.tgz", + "integrity": "sha512-nlppYwq10TBIFqp7qxY0SvbACOXeOjeVL3pOcDsK0FT8XjrEXh9/+lkg8AEIzD16z7YfiJDQjaJG2OLkE7BxNg==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@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/utils/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@mui/x-charts": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@mui/x-charts/-/x-charts-7.8.0.tgz", + "integrity": "sha512-SosaVtx4Ig1nu/loH6Mq4peH5Pq5UvVEnsMfe4G2IEVrMxfwrktWJo+86t9LxiHTERt4wxPKnsqlhkgBIf9ePQ==", + "dependencies": { + "@babel/runtime": "^7.24.7", + "@mui/base": "^5.0.0-beta.40", + "@mui/system": "^5.15.20", + "@mui/utils": "^5.15.20", + "@react-spring/rafz": "^9.7.3", + "@react-spring/web": "^9.7.3", + "clsx": "^2.1.1", + "d3-color": "^3.1.0", + "d3-delaunay": "^6.0.4", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.2.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/material": "^5.15.14", + "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/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@mui/x-data-grid": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-7.11.0.tgz", + "integrity": "sha512-dXaIw3Noxc4d6xenS7J+zMPORG9ptkTW7B81P6QFovILSEuI/qebQhijy/IkqRvcCsuZYLL3nA89bp+EDI503Q==", + "dependencies": { + "@babel/runtime": "^7.24.8", + "@mui/system": "^5.16.2", + "@mui/utils": "^5.16.2", + "@mui/x-internals": "7.11.0", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "reselect": "^4.1.8" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/material": "^5.15.14", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + } + }, + "node_modules/@mui/x-data-grid/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@mui/x-date-pickers": { + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.6.1.tgz", + "integrity": "sha512-erSq5cnOUyBgBmpHnMxIit5yhT3bl/lOaNZKpObvJtvEJetvNA9xWQ7dz/J/AufLzDuvThjusuRD0y+GmeXtiw==", + "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" + }, + "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", + "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" + }, + "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/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@mui/x-internals": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.11.0.tgz", + "integrity": "sha512-GqCYylKiB4cLH9tK4JweJlT2JvPjnpXjS3TEIqtHB4BcSsezhdRrMGzHOO5zCJqkasqTirJh2t6X16Qw1llr4Q==", + "dependencies": { + "@babel/runtime": "^7.24.8", + "@mui/utils": "^5.16.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dependencies": { + "eslint-scope": "5.1.1" + } + }, + "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/@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==", + "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==", + "dependencies": { + "pako": "^1.0.10" + } + }, + "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==", + "dependencies": { + "buffer": "^6.0.3", + "fontkit": "^2.0.2", + "zod": "^3.20.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pdfme/generator": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@pdfme/generator/-/generator-1.2.6.tgz", + "integrity": "sha512-rAkhr4vYa0OxVubAvLI/UIgD9+sCrcBG1SZpFCBVILgZjpqkUsscXdyukRtmHP6WaNAFGINch6PZVoshyQdGPw==", + "dependencies": { + "@pdfme/common": "latest", + "@pdfme/pdf-lib": "^1.17.3", + "atob": "^2.1.2", + "bwip-js": "^3.2.2", + "fontkit": "^2.0.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pdfme/pdf-lib": { + "version": "1.17.3", + "resolved": "https://registry.npmjs.org/@pdfme/pdf-lib/-/pdf-lib-1.17.3.tgz", + "integrity": "sha512-k3cyms42I7jVycwDuzZuLD7A9J/D8Ud1iGJ7BpAfF54QYKxG0mUG6jTDJnc+tHrpNrsoJ4iFqERy5XvMQ6SUsA==", + "dependencies": { + "@pdf-lib/standard-fonts": "^1.0.0", + "@pdf-lib/upng": "^1.0.1", + "pako": "^1.0.11", + "tslib": "^1.11.1" + } + }, + "node_modules/@pdfme/pdf-lib/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@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/@pmmmwh/react-refresh-webpack-plugin": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.10.tgz", + "integrity": "sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA==", + "dependencies": { + "ansi-html-community": "^0.0.8", + "common-path-prefix": "^3.0.0", + "core-js-pure": "^3.23.3", + "error-stack-parser": "^2.0.6", + "find-up": "^5.0.0", + "html-entities": "^2.1.0", + "loader-utils": "^2.0.4", + "schema-utils": "^3.0.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "@types/webpack": "4.x || 5.x", + "react-refresh": ">=0.10.0 <1.0.0", + "sockjs-client": "^1.4.0", + "type-fest": ">=0.17.0 <4.0.0", + "webpack": ">=4.43.0 <6.0.0", + "webpack-dev-server": "3.x || 4.x", + "webpack-hot-middleware": "2.x", + "webpack-plugin-serve": "0.x || 1.x" + }, + "peerDependenciesMeta": { + "@types/webpack": { + "optional": true + }, + "sockjs-client": { + "optional": true + }, + "type-fest": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + }, + "webpack-hot-middleware": { + "optional": true + }, + "webpack-plugin-serve": { + "optional": true + } + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.21", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", + "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", + "dev": true + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@react-aria/ssr": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.7.0.tgz", + "integrity": "sha512-bfufjg4ESE5giN+Fxj1XIzS5f/YIhqcGc+Ve+vUUKU8xZ8t/Xtjlv8F3kjqDBQdk//n3mluFY7xG1wQVB9rMLQ==", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/ssr/node_modules/@swc/helpers": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", + "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@react-spring/animated": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.3.tgz", + "integrity": "sha512-5CWeNJt9pNgyvuSzQH+uy2pvTg8Y4/OisoscZIR8/ZNLIOI+CatFBhGZpDGTF/OzdNFsAoGk3wiUYTwoJ0YIvw==", + "dependencies": { + "@react-spring/shared": "~9.7.3", + "@react-spring/types": "~9.7.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/core": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.3.tgz", + "integrity": "sha512-IqFdPVf3ZOC1Cx7+M0cXf4odNLxDC+n7IN3MDcVCTIOSBfqEcBebSv+vlY5AhM0zw05PDbjKrNmBpzv/AqpjnQ==", + "dependencies": { + "@react-spring/animated": "~9.7.3", + "@react-spring/shared": "~9.7.3", + "@react-spring/types": "~9.7.3" + }, + "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.3", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.3.tgz", + "integrity": "sha512-9vzW1zJPcC4nS3aCV+GgcsK/WLaB520Iyvm55ARHfM5AuyBqycjvh1wbmWmgCyJuX4VPoWigzemq1CaaeRSHhQ==" + }, + "node_modules/@react-spring/shared": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.3.tgz", + "integrity": "sha512-NEopD+9S5xYyQ0pGtioacLhL2luflh6HACSSDUZOwLHoxA5eku1UPuqcJqjwSD6luKjjLfiLOspxo43FUHKKSA==", + "dependencies": { + "@react-spring/types": "~9.7.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/types": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.3.tgz", + "integrity": "sha512-Kpx/fQ/ZFX31OtlqVEFfgaD1ACzul4NksrvIgYfIFq9JpDHFwQkMVZ10tbo0FU/grje4rcL4EIrjekl3kYwgWw==" + }, + "node_modules/@react-spring/web": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.3.tgz", + "integrity": "sha512-BXt6BpS9aJL/QdVqEIX9YoUy8CE6TJrU0mNCqSoxdXlIeNcEBWOfIyE6B14ENNsyQKS3wOWkiJfco0tCr/9tUg==", + "dependencies": { + "@react-spring/animated": "~9.7.3", + "@react-spring/core": "~9.7.3", + "@react-spring/shared": "~9.7.3", + "@react-spring/types": "~9.7.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@remix-run/router": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.18.0.tgz", + "integrity": "sha512-L3jkqmqoSVBVKHfpGZmLrex0lxR5SucGA0sUfFzGctehw+S/ggL9L/0NnC5mw6P8HUWpFZ3nQw3cRApjjWx9Sw==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@restart/hooks": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.10.tgz", + "integrity": "sha512-HVZhYHb+9xnN6vDPyiTmw6N4V5wD9tatL3y0zpHFeeatP1ooOD1edzd3MnJCXYlb3OeleDg+Vv16EikGrH57eA==", + "dependencies": { + "dequal": "^2.0.3" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@restart/ui": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.6.6.tgz", + "integrity": "sha512-eC3puKuWE1SRYbojWHXnvCNHGgf3uzHCb6JOhnF4OXPibOIPEkR1sqDSkL643ydigxwh+ruCa1CmYHlzk7ikKA==", + "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.2", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.2.tgz", + "integrity": "sha512-/GDx+K1STGtpgTsj5Dj3J51YaKxZDblbCQHTH1zHLuoBEWodj6MjtRVv3TUijj1JYLRLSFsFzN8NV4M3QV4d9w==", + "peerDependencies": { + "react": ">=16.14.0" + } + }, + "node_modules/@rollup/plugin-babel": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", + "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", + "dependencies": { + "@babel/helper-module-imports": "^7.10.4", + "@rollup/pluginutils": "^3.1.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^1.20.0||^2.0.0" + }, + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", + "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/plugin-replace": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", + "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "magic-string": "^0.25.7" + }, + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/pluginutils/node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.2.tgz", + "integrity": "sha512-V+MvGwaHH03hYhY+k6Ef/xKd6RYlc4q8WBx+2ANmipHJcKuktNcI/NgEsJgdSUF6Lw32njT6OnrRsKYCdgHjYw==" + }, + "node_modules/@shikijs/core": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.10.3.tgz", + "integrity": "sha512-D45PMaBaeDHxww+EkcDQtDAtzv00Gcsp72ukBtaLSmqRvh0WgGMq3Al0rl1QQBZfuneO75NXMIzEZGFitThWbg==", + "peer": true, + "dependencies": { + "@types/hast": "^3.0.4" + } + }, + "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==", + "license": "MIT" + }, + "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": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@surma/rollup-plugin-off-main-thread": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", + "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", + "dependencies": { + "ejs": "^3.1.6", + "json5": "^2.2.0", + "magic-string": "^0.25.0", + "string.prototype.matchall": "^4.0.6" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.5.1.tgz", + "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/@svgr/plugin-svgo": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz", + "integrity": "sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ==", + "dependencies": { + "cosmiconfig": "^7.0.0", + "deepmerge": "^4.2.2", + "svgo": "^1.2.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/webpack": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.5.0.tgz", + "integrity": "sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g==", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/plugin-transform-react-constant-elements": "^7.12.1", + "@babel/preset-env": "^7.12.1", + "@babel/preset-react": "^7.12.5", + "@svgr/core": "^5.5.0", + "@svgr/plugin-jsx": "^5.5.0", + "@svgr/plugin-svgo": "^5.5.0", + "loader-utils": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/webpack/node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/webpack/node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/webpack/node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz", + "integrity": "sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/webpack/node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz", + "integrity": "sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/webpack/node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz", + "integrity": "sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/webpack/node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz", + "integrity": "sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/webpack/node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz", + "integrity": "sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/webpack/node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz", + "integrity": "sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/webpack/node_modules/@svgr/babel-preset": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-5.5.0.tgz", + "integrity": "sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "^5.0.1", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^5.0.1", + "@svgr/babel-plugin-svg-dynamic-title": "^5.4.0", + "@svgr/babel-plugin-svg-em-dimensions": "^5.4.0", + "@svgr/babel-plugin-transform-react-native-svg": "^5.4.0", + "@svgr/babel-plugin-transform-svg-component": "^5.5.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/webpack/node_modules/@svgr/core": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz", + "integrity": "sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==", + "dependencies": { + "@svgr/plugin-jsx": "^5.5.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/webpack/node_modules/@svgr/hast-util-to-babel-ast": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz", + "integrity": "sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==", + "dependencies": { + "@babel/types": "^7.12.6" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/webpack/node_modules/@svgr/plugin-jsx": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz", + "integrity": "sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==", + "dependencies": { + "@babel/core": "^7.12.3", + "@svgr/babel-preset": "^5.5.0", + "@svgr/hast-util-to-babel-ast": "^5.5.0", + "svg-parser": "^2.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/webpack/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@svgr/webpack/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/@swc/helpers": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", + "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "dependencies": { + "defer-to-connect": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@testing-library/dom": { + "version": "7.31.2", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", + "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^4.2.0", + "aria-query": "^4.2.2", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.6", + "lz-string": "^1.4.4", + "pretty-format": "^26.6.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/@testing-library/dom/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/@testing-library/jest-dom": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.5.tgz", + "integrity": "sha512-AguB9yvTXmCnySBP1lWjfNNUwpbElsaQ567lt2VdGqAdHtpieLgjmcVyv1q7PMIvLbgpDdkWV5Ydv3FEejyp2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.3.2", + "@babel/runtime": "^7.9.2", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.21", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + }, + "peerDependencies": { + "@jest/globals": ">= 28", + "@types/bun": "latest", + "@types/jest": ">= 28", + "jest": ">= 28", + "vitest": ">= 0.32" + }, + "peerDependenciesMeta": { + "@jest/globals": { + "optional": true + }, + "@types/bun": { + "optional": true + }, + "@types/jest": { + "optional": true + }, + "jest": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/react": { + "version": "11.2.7", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-11.2.7.tgz", + "integrity": "sha512-tzRNp7pzd5QmbtXNG/mhdcl7Awfu/Iz1RaVHY75zTdOkmHCuzMhRL83gWHSgOAcjS3CCbyfwUHMZgRJb4kAfpA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@testing-library/dom": "^7.28.1" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "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==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, + "node_modules/@types/babel__core": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", + "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==", + "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/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz", + "integrity": "sha512-4x5FkPpLipqwthjPsF7ZRbOv3uoLUFkTA9G9v583qi4pACvq0uTELrB8OLUzPWUI4IJIyvM85vzkV1nyiI2Lig==", + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "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==", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==" + }, + "node_modules/@types/express": { + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.35", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz", + "integrity": "sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "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==", + "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==", + "peer": true, + "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.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" + }, + "node_modules/@types/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.11", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.11.tgz", + "integrity": "sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/inquirer": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-9.0.7.tgz", + "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==" + }, + "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==", + "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==", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.12", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", + "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/jest/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, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@types/jest/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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "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==" + }, + "node_modules/@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + }, + "node_modules/@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "optional": true, + "peer": true + }, + "node_modules/@types/node": { + "version": "20.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", + "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "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/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "optional": true, + "peer": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "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==", + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" + }, + "node_modules/@types/q": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", + "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==" + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" + }, + "node_modules/@types/react": { + "version": "17.0.62", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.62.tgz", + "integrity": "sha512-eANCyz9DG8p/Vdhr0ZKST8JV12PhH2ACCDYlFw6DIO+D+ca+uP4jtEDEpVqXZrh/uZdXQGwk7whJa3ah5DtyLw==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-beautiful-dnd": { + "version": "13.1.8", + "resolved": "https://registry.npmjs.org/@types/react-beautiful-dnd/-/react-beautiful-dnd-13.1.8.tgz", + "integrity": "sha512-E3TyFsro9pQuK4r8S/OL6G99eq7p8v29sX0PM7oT8Z+PJfZvSQTx4zTQbUJ+QZXioAF0e7TGBEcA1XhYhCweyQ==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-bootstrap": { + "version": "0.32.32", + "resolved": "https://registry.npmjs.org/@types/react-bootstrap/-/react-bootstrap-0.32.32.tgz", + "integrity": "sha512-GM9UtV7v+C2F0rbqgIpMWdCKBMdX3PQURoJQobPO4vDAeFadcExNtKffi13/MjaAks+riJKVGyiMe+6OmDYT2w==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-datepicker": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@types/react-datepicker/-/react-datepicker-4.11.2.tgz", + "integrity": "sha512-ELYyX3lb3K1WltqdlF1hbnaDGgzlF6PIR5T4W38cSEcfrQDIrPE+Ioq5pwRe/KEJ+ihHMjvTVZQkwJx0pWMNHQ==", + "dev": true, + "dependencies": { + "@popperjs/core": "^2.9.2", + "@types/react": "*", + "date-fns": "^2.0.1", + "react-popper": "^2.2.5" + } + }, + "node_modules/@types/react-dom": { + "version": "17.0.20", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.20.tgz", + "integrity": "sha512-4pzIjSxDueZZ90F52mU3aPoogkHIoSIDG+oQ+wQK7Cy2B9S+MvOqY0uEA/qawKz381qrEDkvpwyt8Bm31I8sbA==", + "dev": true, + "dependencies": { + "@types/react": "^17" + } + }, + "node_modules/@types/react-google-recaptcha": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/react-google-recaptcha/-/react-google-recaptcha-2.1.5.tgz", + "integrity": "sha512-iWTjmVttlNgp0teyh7eBXqNOQzVq2RWNiFROWjraOptRnb1OcHJehQnji0sjqIRAk9K0z8stjyhU+OLpPb0N6w==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-redux": { + "version": "7.1.25", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.25.tgz", + "integrity": "sha512-bAGh4e+w5D8dajd6InASVIyCo4pZLJ66oLb80F9OBLO1gKESbZcRCJpTT6uLXX+HAB57zw1WTdwJdAsewuTweg==", + "dependencies": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, + "node_modules/@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "dev": true, + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "dev": true, + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + }, + "node_modules/@types/sanitize-html": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.11.0.tgz", + "integrity": "sha512-7oxPGNQHXLHE48r/r/qjn7q0hlrs3kL7oZnGj0Wf/h9tj/6ibFyRkNbsDxaBBZ4XUZ0Dx5LGCyDJ04ytSofacQ==", + "dev": true, + "dependencies": { + "htmlparser2": "^8.0.0" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", + "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" + }, + "node_modules/@types/semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==" + }, + "node_modules/@types/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", + "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.2.tgz", + "integrity": "sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw==", + "dependencies": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "dependencies": { + "@types/node": "*" + } + }, + "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==" + }, + "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/trusted-types": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz", + "integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==" + }, + "node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==", + "peer": true + }, + "node_modules/@types/warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz", + "integrity": "sha512-t/Tvs5qR47OLOr+4E9ckN8AmP2Tf16gWq+/qA4iUGS/OOyHVO8wv2vjJuX8SNOUTJyWb+2t7wJm6cXILFnOROA==" + }, + "node_modules/@types/ws": { + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", + "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", + "dependencies": { + "@types/node": "*" + } + }, + "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==", + "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==" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/experimental-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.62.0.tgz", + "integrity": "sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==", + "dependencies": { + "@typescript-eslint/utils": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "dependencies": { + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "dependencies": { + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@wry/context": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.7.3.tgz", + "integrity": "sha512-Nl8WTesHp89RF803Se9X3IiHjdmLBrIvPMaJkl+rKVJAYyPsz1TEUbu89943HpvujtSJgDUx9W4vZw3K1Mr3sA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wry/equality": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.5.6.tgz", + "integrity": "sha512-D46sfMTngaYlrH+OspKf8mIJETntFnf6Hsjb0V41jAXJ7Bx2kB8Rv8RCUujuVWYttFtHkUNp7g+FwxNQAr6mXA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wry/trie": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.4.3.tgz", + "integrity": "sha512-I6bHwH0fSf6RqQcnnXLJKhkSXG45MFral3GxPaY4uAl0LYDZM+YDVDAiU9bYwjTuysy1S0IeecWtmq1SZA3M1w==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==" + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "optional": true, + "peer": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "bin": { + "acorn": "bin/acorn" + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dependencies": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "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==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agentkeepalive": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", + "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", + "optional": true, + "peer": true, + "dependencies": { + "debug": "^4.1.0", + "depd": "^2.0.0", + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "optional": true, + "peer": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "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/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "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": { + "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": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "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": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, + "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==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "optional": true, + "peer": true + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "optional": true, + "peer": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "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==", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "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==", + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + }, + "node_modules/array-includes": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", + "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.reduce": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz", + "integrity": "sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.toreversed": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", + "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz", + "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.1.0", + "es-shim-unscopables": "^1.0.2" + } + }, + "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==", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "optional": true, + "peer": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==" + }, + "node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + }, + "node_modules/async-foreach": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "integrity": "sha512-VUeSMD8nEGBWaZK4lizI1sf3yEC7pnAQ/mrI7pC2fBz2s/tq5jWWEngTwaf0Gruu/OoXRGLGg1XFqpYBiGTYJA==", + "optional": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "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/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "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/autolinker": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-0.28.1.tgz", + "integrity": "sha512-zQAFO1Dlsn69eXaO6+7YZc+v84aquQKbwpzCE3L0stj56ERn9hutFxPopViLjo9G+rWwjozRhgS5KJ25Xy19cQ==", + "dependencies": { + "gulp-header": "^1.7.1" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.14", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", + "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], + "dependencies": { + "browserslist": "^4.21.5", + "caniuse-lite": "^1.0.30001464", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.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==", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "optional": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", + "optional": true, + "peer": true + }, + "node_modules/axe-core": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.2.tgz", + "integrity": "sha512-zIURGIS1E1Q4pcrMjp+nnEh+16G56eG/MUllJH8yEvw7asDo7Ac9uhC9KIH5jzpITueEZolfYglnCGIuSBz39g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", + "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "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==", + "license": "MIT", + "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" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-jest/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "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==", + "license": "MIT", + "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/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==", + "license": "MIT" + }, + "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==", + "license": "MIT", + "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" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-jest/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "license": "MIT", + "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" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/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==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "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==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/babel-loader": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.3.0.tgz", + "integrity": "sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==", + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-loader/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/babel-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/babel-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/babel-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/babel-loader/node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "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==", + "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" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "MIT", + "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_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/babel-plugin-named-asset-import": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz", + "integrity": "sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==", + "peerDependencies": { + "@babel/core": "^7.1.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.8.tgz", + "integrity": "sha512-OtIuQfafSzpo/LhnJaykc0R/MMnuLSSVjVYy9mHArIZ9qTCSZ6TpWCuEKZYVoN//t8HqBNScHrOtCrIK5IaGLg==", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.5.0", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", + "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.2.tgz", + "integrity": "sha512-Cid+Jv1BrY9ReW9lIfNlNpsI53N+FN7gE+f73zLAUbr9C52W4gKLWSByx47pfDJsEysojKArqOtOKZSVIIUTuQ==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.1", + "core-js-compat": "^3.31.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz", + "integrity": "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.5.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator/node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", + "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-transform-react-remove-prop-types": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", + "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==" + }, + "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==", + "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/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==", + "license": "MIT", + "dependencies": { + "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/babel-preset-react-app": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-10.0.1.tgz", + "integrity": "sha512-b0D9IZ1WhhCWkrTXyFuIIgqGzSkRIH5D5AmB0bXbzYAB1OBAwHcUeyWW2LorutLWF5btNo/N7r/cIdmvvKJlYg==", + "dependencies": { + "@babel/core": "^7.16.0", + "@babel/plugin-proposal-class-properties": "^7.16.0", + "@babel/plugin-proposal-decorators": "^7.16.4", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.0", + "@babel/plugin-proposal-numeric-separator": "^7.16.0", + "@babel/plugin-proposal-optional-chaining": "^7.16.0", + "@babel/plugin-proposal-private-methods": "^7.16.0", + "@babel/plugin-transform-flow-strip-types": "^7.16.0", + "@babel/plugin-transform-react-display-name": "^7.16.0", + "@babel/plugin-transform-runtime": "^7.16.4", + "@babel/preset-env": "^7.16.4", + "@babel/preset-react": "^7.16.0", + "@babel/preset-typescript": "^7.16.0", + "@babel/runtime": "^7.16.3", + "babel-plugin-macros": "^3.1.0", + "babel-plugin-transform-react-remove-prop-types": "^0.4.24" + } + }, + "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/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/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "optional": true, + "peer": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bfj": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.0.2.tgz", + "integrity": "sha512-+e/UqUzwmzJamNF50tBV6tZPTORow7gQ96iFow+8b562OdMpEK0BcJEq2OSPEDmAbSMBQ7PKZ87ubFkgxpYWgw==", + "dependencies": { + "bluebird": "^3.5.5", + "check-types": "^11.1.1", + "hoopy": "^0.1.4", + "tryer": "^1.0.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "engines": { + "node": "*" + } + }, + "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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "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" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/body-parser/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bonjour-service": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", + "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==", + "dependencies": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "node_modules/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/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": { + "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": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "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==", + "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/boxen/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "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==", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "BSD-2-Clause" + }, + "node_modules/browserslist": { + "version": "4.23.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", + "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001640", + "electron-to-chromium": "^1.4.820", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "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/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bwip-js": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/bwip-js/-/bwip-js-3.4.3.tgz", + "integrity": "sha512-x+mQE/bq5V0Nlkn4Jd4cktNlEPH4zeIGSOEQNUtsV/cCJNiBba7u/S9PYR1pmD2WDeeZAIbYTjvGHjBQ21RXvw==", + "bin": { + "bwip-js": "bin/bwip-js.js" + } + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "engines": { + "node": ">= 0.8" + } + }, + "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": { + "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_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": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": ">=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==", + "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==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "optional": true, + "peer": true, + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001645", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001645.tgz", + "integrity": "sha512-GFtY2+qt91kzyMk6j48dJcwJVq5uTkk71XxE3RtScx7XWRLsO7bU44LOFkOZYR8w9YMS0UhPSYpN/6rAMImmLw==", + "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" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "optional": true, + "peer": true + }, + "node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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==", + "engines": { + "node": ">=10" + } + }, + "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/check-types": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.2.tgz", + "integrity": "sha512-HBiYvXvn9Z70Z88XKjz3AEKd4HJhBXsa3j7xFnITAzoS8+q6eIGi8qDB8FKPBAjtuxjI/zFpwuiCb8oDtKOYrA==" + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "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": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "optional": true, + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "engines": { + "node": ">=6.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==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", + "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", + "license": "MIT" + }, + "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/clean-css": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz", + "integrity": "sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "optional": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dev": true, + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "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.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": ">=12" + }, + "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" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "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": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "dependencies": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/coa/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/coa/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/coa/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/coa/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/coa/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/coa/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/coa/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/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.8.0" + } + }, + "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/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" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "optional": true, + "peer": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" + }, + "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==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" + }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/compression/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-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "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/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": { + "safe-buffer": "~5.1.0" + } + }, + "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/concat-with-sourcemaps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "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": { + "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": ">=8" + } + }, + "node_modules/confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==" + }, + "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": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "engines": { + "node": ">=0.8" + } + }, + "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": { + "ms": "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/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "optional": true, + "peer": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/core-js": { + "version": "3.31.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.31.1.tgz", + "integrity": "sha512-2sKLtfq1eFST7l7v62zaqXacPc7uG8ZAya8ogijLhTtaKNcpzpB4TMoTw2Si+8GYKRwFPMMtUT0263QFWFfqyQ==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.0.tgz", + "integrity": "sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==", + "dependencies": { + "browserslist": "^4.22.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-pure": { + "version": "3.31.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.31.1.tgz", + "integrity": "sha512-w+C62kvWti0EPs4KPMCMVv9DriHSXfQOCQ94bGGBiEW5rrbtt/Rz8n5Krhfw9cpFyzXBjf3DB3QnPdEzGDY4Fw==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "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/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/create-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==", + "license": "MIT", + "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/create-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==", + "license": "MIT", + "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" + } + }, + "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": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.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_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/css-blank-pseudo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", + "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-blank-pseudo": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "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" + } + }, + "node_modules/css-declaration-sorter": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", + "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-has-pseudo": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", + "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-has-pseudo": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-loader": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz", + "integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.21", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.3", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/css-minimizer-webpack-plugin": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz", + "integrity": "sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==", + "dependencies": { + "cssnano": "^5.0.6", + "jest-worker": "^27.0.2", + "postcss": "^8.3.5", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@parcel/css": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/css-prefers-color-scheme": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", + "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", + "bin": { + "css-prefers-color-scheme": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "node_modules/css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" + }, + "node_modules/css-select/node_modules/css-what": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-select/node_modules/dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "dependencies": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + } + }, + "node_modules/css-select/node_modules/domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/css-select/node_modules/domutils/node_modules/domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, + "node_modules/css-select/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/css-select/node_modules/nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dependencies": { + "boolbase": "~1.0.0" + } + }, + "node_modules/css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", + "dependencies": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-tree/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true + }, + "node_modules/cssdb": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.6.0.tgz", + "integrity": "sha512-Nna7rph8V0jC6+JBY4Vk4ndErUmfJfV6NJCaZdurL0omggabiy+QB2HCQtu5c/ACLZ0I7REv7A4QyPIoYzZx0w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + } + ] + }, + "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==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "5.1.15", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", + "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", + "dependencies": { + "cssnano-preset-default": "^5.2.14", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-default": { + "version": "5.2.14", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "dependencies": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "node_modules/csso/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "license": "MIT" + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "license": "MIT", + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "MIT" + }, + "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": { + "lodash.flow": "^3.5.0" + } + }, + "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": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "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/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": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "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/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/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_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": { + "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/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" + }, + "engines": { + "node": ">=12" + } + }, + "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/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": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==" + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "optional": true, + "peer": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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==", + "devOptional": true, + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/dayjs": { + "version": "1.11.11", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", + "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "optional": true, + "peer": true, + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "license": "MIT" + }, + "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": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/dedent": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": 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==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "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/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/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dependencies": { + "clone": "^1.0.2" + }, + "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/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": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "engines": { + "node": ">=8" + } + }, + "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": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "optional": true, + "peer": true + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "node_modules/detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "dependencies": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "bin": { + "detect": "bin/detect-port", + "detect-port": "bin/detect-port" + }, + "engines": { + "node": ">= 4.2.1" + } + }, + "node_modules/detect-port-alt/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/detect-port-alt/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "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_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + }, + "node_modules/dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==" + }, + "node_modules/dns-packet": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.0.tgz", + "integrity": "sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ==", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dependencies": { + "utila": "~0.4" + } + }, + "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": { + "@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/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "deprecated": "Use your platform's native DOMException instead", + "license": "MIT", + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/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": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "engines": { + "node": ">=10" + } + }, + "node_modules/dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, + "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/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "optional": true, + "peer": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "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==" + }, + "node_modules/ejs": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", + "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz", + "integrity": "sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA==", + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "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==" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "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" + } + }, + "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": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.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" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "optional": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "optional": true, + "peer": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/es-abstract": { + "version": "1.23.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.2.tgz", + "integrity": "sha512-60s3Xv2T2p1ICykc7c+DNDPLDMm9t4QxCOUU0K9JxiLjM3C1zB9YVdN7tjxrFd4+AkZ8CdX1ovUga4P2+1e+/w==", + "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.7", + "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.5", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" + }, + "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": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz", + "integrity": "sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", + "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==" + }, + "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==", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "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==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "license": "MIT", + "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/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "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/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "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==", + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint": { + "version": "8.45.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.45.0.tgz", + "integrity": "sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.1.0", + "@eslint/js": "8.44.0", + "@humanwhocodes/config-array": "^0.11.10", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "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.0", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.6.0", + "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": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-config-react-app": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", + "integrity": "sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==", + "dependencies": { + "@babel/core": "^7.16.0", + "@babel/eslint-parser": "^7.16.3", + "@rushstack/eslint-patch": "^1.1.0", + "@typescript-eslint/eslint-plugin": "^5.5.0", + "@typescript-eslint/parser": "^5.5.0", + "babel-preset-react-app": "^10.0.1", + "confusing-browser-globals": "^1.0.11", + "eslint-plugin-flowtype": "^8.0.3", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jest": "^25.3.0", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.27.1", + "eslint-plugin-react-hooks": "^4.3.0", + "eslint-plugin-testing-library": "^5.0.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "eslint": "^8.0.0" + } + }, + "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==", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-flowtype": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz", + "integrity": "sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==", + "dependencies": { + "lodash": "^4.17.21", + "string-natural-compare": "^3.0.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@babel/plugin-syntax-flow": "^7.14.5", + "@babel/plugin-transform-react-jsx": "^7.14.9", + "eslint": "^8.1.0" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "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==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.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==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jest": { + "version": "25.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz", + "integrity": "sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==", + "dependencies": { + "@typescript-eslint/experimental-utils": "^5.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^4.0.0 || ^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", + "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", + "dependencies": { + "@babel/runtime": "^7.20.7", + "aria-query": "^5.1.3", + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.6.2", + "axobject-query": "^3.1.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "has": "^1.0.3", + "jsx-ast-utils": "^3.3.3", + "language-tags": "=1.0.5", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.34.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz", + "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==", + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlast": "^1.2.4", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.3", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.17", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7", + "object.hasown": "^1.1.3", + "object.values": "^1.1.7", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.10" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_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==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-testing-library": { + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.11.0.tgz", + "integrity": "sha512-ELY7Gefo+61OfXKlQeXNIDVVLPcvKTeiQOoMZG9TeuWa7Ln4dUNRv8JdRWBQI9Mbb427XGlVB1aa1QPZxBJM8Q==", + "dependencies": { + "@typescript-eslint/utils": "^5.58.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0", + "npm": ">=6" + }, + "peerDependencies": { + "eslint": "^7.5.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-tsdoc": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.17.tgz", + "integrity": "sha512-xRmVi7Zx44lOBuYqG8vzTXuL6IdGOeF9nHX17bjJ8+VE6fsxpdGem0/SBTmAwgYMKYB1WBkqRJVQ+n8GK041pA==", + "dev": true, + "dependencies": { + "@microsoft/tsdoc": "0.14.2", + "@microsoft/tsdoc-config": "0.16.2" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz", + "integrity": "sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==", + "dependencies": { + "@types/eslint": "^7.29.0 || ^8.4.1", + "jest-worker": "^28.0.2", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/eslint/node_modules/eslint-scope": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.1.tgz", + "integrity": "sha512-CvefSOsDdaYYvxChovdrPo/ZGt8d5lrJWleAc1diXRKhHGiTYEI26cvo8Kle/wGnsizoCJjK73FMg1/IkIwiNA==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "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==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "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" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "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/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "engines": { + "node": ">= 0.8.0" + } + }, + "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": { + "fill-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-range/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/expect/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/expect/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/expect/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "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/expect/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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/expect/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==", + "license": "MIT", + "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" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/express/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/express/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "optional": true, + "peer": true + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/external-editor/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "engines": [ + "node >=0.6.0" + ], + "optional": true, + "peer": true + }, + "node_modules/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.0", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz", + "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + }, + "node_modules/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/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dependencies": { + "bser": "2.1.1" + } + }, + "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" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/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==", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/file-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/filesize": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", + "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", + "engines": { + "node": ">= 0.4.0" + } + }, + "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": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "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" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-node-modules": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.3.tgz", + "integrity": "sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg==", + "dev": true, + "dependencies": { + "findup-sync": "^4.0.0", + "merge": "^2.1.1" + } + }, + "node_modules/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==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/findup-sync": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/flag-icons": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/flag-icons/-/flag-icons-6.7.0.tgz", + "integrity": "sha512-+KXrrrXN2jiETFxisFl+3f83Bq7tj5nuIWnbv9fX59k05lvldEXRCOffybb5hAIjMWt4nmG0E8OfKt7Flm99Eg==" + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" + }, + "node_modules/follow-redirects": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/fontkit": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.2.tgz", + "integrity": "sha512-jc4k5Yr8iov8QfS6u8w2CnHWVmbOGtdBtOXMze5Y+QD966Rx6PEVWXSEGwXlsDlKtu1G12cJjcsybnqhSk/+LA==", + "dependencies": { + "@swc/helpers": "^0.4.2", + "brotli": "^1.3.2", + "clone": "^2.1.2", + "dfa": "^1.2.0", + "fast-deep-equal": "^3.1.3", + "restructure": "^3.0.0", + "tiny-inflate": "^1.0.3", + "unicode-properties": "^1.4.0", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "optional": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", + "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", + "dependencies": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "chokidar": "^3.4.2", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=10", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "eslint": ">= 6", + "typescript": ">= 2.7", + "vue-template-compiler": "*", + "webpack": ">= 4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dependencies": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "optional": true, + "peer": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.4.tgz", + "integrity": "sha512-INM/fWAxMICjttnD0DX1rBvinKskj5G1w+oy/pnm9u/tSlnBrzFonJMcalKJ30P8RRsPzKcCG7Q8l0jx5Fh9YQ==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "optional": true, + "peer": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "optional": true, + "peer": true, + "dependencies": { + "globule": "^1.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "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": { + "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": ">=6.9.0" + } + }, + "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": "6.* || 8.* || >= 10.*" + } + }, + "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": ">=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==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", + "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "optional": true, + "peer": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "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==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "node_modules/global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "dev": true, + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-dirs/node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "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==", + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globule": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.4.tgz", + "integrity": "sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==", + "optional": true, + "peer": true, + "dependencies": { + "glob": "~7.1.1", + "lodash": "^4.17.21", + "minimatch": "~3.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/globule/node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "optional": true, + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globule/node_modules/minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "optional": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "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==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" + }, + "node_modules/graphql": { + "version": "16.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": { + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/graphql-ws": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.16.0.tgz", + "integrity": "sha512-Ju2RCU2dQMgSKtArPbEtsK5gNLnsQyTNIo/T7cZNp96niC1x0KdJNZV0TIoilceBPQwfb5itrGl8pkFeOUMl4A==", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "graphql": ">=0.11 <=16" + } + }, + "node_modules/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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gray-matter/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-header": { + "version": "1.8.12", + "resolved": "https://registry.npmjs.org/gulp-header/-/gulp-header-1.8.12.tgz", + "integrity": "sha512-lh9HLdb53sC7XIZOYzTXM4lFuXElv3EVkSDhsd7DoJBj7hm+Ni7D3qYbb+Rr8DuM8nRanBvkVO9d7askreXGnQ==", + "deprecated": "Removed event-stream from gulp-header", + "dependencies": { + "concat-with-sourcemaps": "*", + "lodash.template": "^4.4.0", + "through2": "^2.0.0" + } + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "optional": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "optional": true, + "peer": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/har-validator/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "optional": true, + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/har-validator/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "optional": true, + "peer": true + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "optional": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/harmony-reflect": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", + "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==" + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/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": { + "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": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "optional": true, + "peer": true + }, + "node_modules/has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, + "node_modules/history": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz", + "integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==", + "dependencies": { + "@babel/runtime": "^7.7.6" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hoopy": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", + "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "optional": true, + "peer": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true, + "peer": true + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "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/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/html-entities": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", + "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "license": "MIT" + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "engines": { + "node": ">= 12" + } + }, + "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-webpack-plugin": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz", + "integrity": "sha512-6YrDKTuqaP/TquFH7h4srYWsZx+x6k6+FbsTm0ziCwGHDP78Unr1r9F/H4+sGmMbX08GQcJ+K64x55b+7VM/jg==", + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "webpack": "^5.20.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/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "devOptional": true + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "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==", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "optional": true, + "peer": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "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==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "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==", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "optional": true, + "peer": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/husky": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", + "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "dev": true, + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/i18next": { + "version": "21.10.0", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.10.0.tgz", + "integrity": "sha512-YeuIBmFsGjUfO3qBmMOc0rQaun4mIpGKET5WDwvu8lU7gvwpcariZLNtL0Fzj+zazcHUrlXHiptcFhBMFaxzfg==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "dependencies": { + "@babel/runtime": "^7.17.2" + } + }, + "node_modules/i18next-browser-languagedetector": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz", + "integrity": "sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==", + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, + "node_modules/i18next-http-backend": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.5.2.tgz", + "integrity": "sha512-+K8HbDfrvc1/2X8jpb7RLhI9ZxBDpx3xogYkQwGKlWAUXLSEGXzgdt3EcUjLlBCdMwdQY+K+EUF6oh8oB6rwHw==", + "dependencies": { + "cross-fetch": "4.0.0" + } + }, + "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==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==" + }, + "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==", + "dependencies": { + "harmony-reflect": "^1.4.6" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/immutable": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", + "devOptional": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "license": "MIT", + "dependencies": { + "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/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "devOptional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "optional": true, + "peer": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "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==" + }, + "node_modules/inquirer": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", + "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^6.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "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==", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "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_modules/ip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==", + "optional": true, + "peer": true + }, + "node_modules/ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "engines": { + "node": ">= 10" + } + }, + "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==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "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.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "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==", + "license": "MIT", + "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/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": ">=0.10.0" + } + }, + "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": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "optional": true, + "peer": true + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==" + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-npm": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", + "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", + "dev": true, + "engines": { + "node": ">=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==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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==", + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "optional": true, + "peer": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "engines": { + "node": ">=8" + } + }, + "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==", + "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" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "bin": { + "semver": "bin/semver.js" + } + }, + "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==", + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, + "node_modules/jake": { + "version": "10.8.7", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", + "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jake/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-changed-files/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-changed-files/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-changed-files/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "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-changed-files/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==", + "license": "MIT", + "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" + } + }, + "node_modules/jest-changed-files/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==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "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==", + "license": "MIT", + "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-circus/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==", + "license": "MIT", + "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" + } + }, + "node_modules/jest-circus/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==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-circus/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/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==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-cli/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-cli/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "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-cli/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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli/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==", + "license": "MIT", + "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" + } + }, + "node_modules/jest-cli/node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli/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==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-config/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-config/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "MIT", + "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-config/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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-config/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==", + "license": "MIT", + "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" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-config/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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-config/node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-config/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==", + "license": "MIT", + "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" + } + }, + "node_modules/jest-config/node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-config/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==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-config/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==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest-config/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/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==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "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==", + "license": "MIT", + "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-diff/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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/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==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "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==", + "license": "MIT", + "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-each/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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/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==", + "license": "MIT", + "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" + } + }, + "node_modules/jest-each/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/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==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "license": "MIT", + "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-environment-jsdom/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==", + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-jsdom/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==", + "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" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-jsdom/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==", + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/jest-environment-jsdom/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==", + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/jest-environment-jsdom/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "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-environment-jsdom/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==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-jsdom/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==", + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-jsdom/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==", + "license": "MIT", + "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-environment-jsdom/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==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-environment-jsdom/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==", + "license": "MIT" + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-environment-node/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "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-environment-node/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==", + "license": "MIT", + "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" + } + }, + "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==", + "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==", + "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": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/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==", + "license": "MIT", + "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" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/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==", + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/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==", + "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" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/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==", + "license": "MIT", + "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-jasmine2/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==", + "license": "MIT", + "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-jasmine2/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==", + "license": "MIT", + "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-jasmine2/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==", + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/jest-jasmine2/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==", + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "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==", + "license": "MIT", + "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-jasmine2/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==", + "license": "MIT", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/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==", + "license": "MIT", + "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" + } + }, + "node_modules/jest-jasmine2/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==", + "license": "MIT", + "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-jasmine2/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==", + "license": "MIT", + "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" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/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==", + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^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-jasmine2/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==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/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==", + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/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==", + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/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==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.5.1", + "semver": "^7.3.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-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==", + "license": "MIT", + "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-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==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-jasmine2/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "license": "MIT" + }, + "node_modules/jest-jasmine2/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==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.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==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-leak-detector/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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-leak-detector/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/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==", + "dev": true, + "dependencies": { + "@jedmao/location": "^3.0.0", + "jest-diff": "^29.6.4" + }, + "engines": { + "node": "^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.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==", + "license": "MIT", + "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-matcher-utils/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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/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==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "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==", + "license": "MIT", + "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-message-util/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/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==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-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==", + "license": "MIT", + "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-mock/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==", + "license": "MIT", + "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" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-preview": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/jest-preview/-/jest-preview-0.3.1.tgz", + "integrity": "sha512-gRR4shnXFSh8tdNaIncJC98d1zXD7w7LA52HQC0bu0DsPb+FXVEg+NQh9GTbO+n6/SCgcZNQAVt4MeCfsIkBPA==", + "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==", + "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-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies/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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-runner/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "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==", + "license": "MIT", + "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-runner/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==", + "license": "MIT" + }, + "node_modules/jest-runner/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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/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==", + "license": "MIT", + "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" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-runner/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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/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==", + "license": "MIT", + "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" + } + }, + "node_modules/jest-runner/node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/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==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/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==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest-runner/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==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-runner/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/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==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-runner/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==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-runner/node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/jest-runner/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==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-runtime/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "MIT", + "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-runtime/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==", + "license": "MIT" + }, + "node_modules/jest-runtime/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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/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==", + "license": "MIT", + "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" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-runtime/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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/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==", + "license": "MIT", + "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" + } + }, + "node_modules/jest-runtime/node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/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==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/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==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest-runtime/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/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==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-runtime/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==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.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==", + "dependencies": { + "@types/node": "*", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/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==", + "license": "MIT" + }, + "node_modules/jest-snapshot/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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/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==", + "license": "MIT", + "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" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-snapshot/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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/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==", + "license": "MIT", + "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" + } + }, + "node_modules/jest-snapshot/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==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/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==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest-snapshot/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/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==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/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==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-validate": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "dependencies": { + "@jest/types": "^27.5.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "leven": "^3.1.0", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-validate/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-validate/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "node_modules/jest-watch-typeahead": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-2.2.2.tgz", + "integrity": "sha512-+QgOFW4o5Xlgd6jGS5X37i08tuuXNW8X0CV9WNFi+3n8ExCIP+E1melYhvYLjv5fE6D0yyzk74vsSO8I6GqtvQ==", + "license": "MIT", + "dependencies": { + "ansi-escapes": "^6.0.0", + "chalk": "^5.2.0", + "jest-regex-util": "^29.0.0", + "jest-watcher": "^29.0.0", + "slash": "^5.0.0", + "string-length": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "jest": "^27.0.0 || ^28.0.0 || ^29.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/ansi-escapes": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", + "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watch-typeahead/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==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/jest-watch-typeahead/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-watch-typeahead/node_modules/char-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.1.tgz", + "integrity": "sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw==", + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/jest-watch-typeahead/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==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watch-typeahead/node_modules/string-length": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-5.0.1.tgz", + "integrity": "sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==", + "license": "MIT", + "dependencies": { + "char-regex": "^2.0.0", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watch-typeahead/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-watcher/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-watcher/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "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==", + "license": "MIT", + "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-watcher/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==", + "license": "MIT", + "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" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/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==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/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==", + "license": "MIT", + "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/jiti": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz", + "integrity": "sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true + }, + "node_modules/js-base64": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", + "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==", + "optional": true, + "peer": true + }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "engines": { + "node": ">=14" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "optional": true, + "peer": true + }, + "node_modules/jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "license": "MIT", + "dependencies": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "optional": true, + "peer": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "optional": true, + "peer": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.4.tgz", + "integrity": "sha512-fX2TVdCViod6HwKEtSWGHs57oFhVfCMwieb9PuRDgjDPh5XeqJiHFFFJCHxU5cnTc3Bu/GRL+kPiFmw8XWOfKw==", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.0" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "engines": { + "node": ">=6" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==" + }, + "node_modules/language-tags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", + "dependencies": { + "language-subtag-registry": "~0.3.2" + } + }, + "node_modules/latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "dependencies": { + "package-json": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/launch-editor": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz", + "integrity": "sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==", + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.7.3" + } + }, + "node_modules/lazy-cache": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", + "integrity": "sha512-7vp2Acd2+Kz4XkzxGxaB1FWOi8KjWIWsgdfD5MCb86DWvlLqhRPM+d6Pro3iNEL5VT9mstz5hKAlcd+QR6H3aA==", + "dependencies": { + "set-getter": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "engines": { + "node": ">=10" + } + }, + "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/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==", + "peer": true, + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/lint-staged": { + "version": "15.2.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.7.tgz", + "integrity": "sha512-+FdVbbCZ+yoh7E/RosSdqKJyUM2OEjTciH0TFNkawKgvFp1zbGlEC39RADg+xKBG1R4mhoH2j85myBQZ5wR+lw==", + "dev": true, + "dependencies": { + "chalk": "~5.3.0", + "commander": "~12.1.0", + "debug": "~4.3.4", + "execa": "~8.0.1", + "lilconfig": "~3.1.1", + "listr2": "~8.2.1", + "micromatch": "~4.0.7", + "pidtree": "~0.6.0", + "string-argv": "~0.3.2", + "yaml": "~2.4.2" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "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" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "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, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/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_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, + "engines": { + "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/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==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lint-staged/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "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": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/yaml": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", + "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", + "dev": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/list-item": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/list-item/-/list-item-1.1.1.tgz", + "integrity": "sha512-S3D0WZ4J6hyM8o5SNKWaMYB1ALSacPZ2nHGEuCjmHZ+dc03gFeNZoNDcqfcnO4vDhTZmNrqrpYZCdXsRh22bzw==", + "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" + } + }, + "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": { + "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": ">=0.10.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==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/listr2": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.1.tgz", + "integrity": "sha512-irTfvpib/rNiD637xeevjO2l3Z5loZmuaRi0L0YE5LfijwVY96oyVn0DFD3o/teAok7nfobMG1THvvcHh/BP6g==", + "dev": true, + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.0.0", + "rfdc": "^1.3.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_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/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": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "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.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/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, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "engines": { + "node": ">=6.11.5" + } + }, + "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==", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "node_modules/lodash.flow": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", + "integrity": "sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" + }, + "node_modules/lodash.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "dependencies": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "node_modules/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/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-update": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.0.0.tgz", + "integrity": "sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==", + "dev": true, + "dependencies": { + "ansi-escapes": "^6.2.0", + "cli-cursor": "^4.0.0", + "slice-ansi": "^7.0.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", + "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "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": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "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==", + "dev": true, + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "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/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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==", + "peer": true + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "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==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "peer": 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" + }, + "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==", + "peer": true + }, + "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": ">=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==", + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/math-random": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", + "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==" + }, + "node_modules/mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==" + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "peer": true + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "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/meow": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", + "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", + "optional": true, + "peer": true, + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize": "^1.2.0", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "optional": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", + "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", + "dev": true + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "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": ">=4" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "devOptional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.7.6", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz", + "integrity": "sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw==", + "dependencies": { + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/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/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "optional": true, + "peer": true, + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "optional": true, + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "optional": true, + "peer": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "optional": true, + "peer": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "optional": true, + "peer": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "optional": true, + "peer": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true, + "peer": true + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "optional": true, + "peer": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true, + "peer": true + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "optional": true, + "peer": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mrmime": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "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/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", + "optional": true, + "peer": true + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "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" + }, + "engines": { + "node": "4.x || >=6.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-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-gyp": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "optional": true, + "peer": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/node-gyp/node_modules/@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "optional": true, + "peer": true, + "dependencies": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "node_modules/node-gyp/node_modules/@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "optional": true, + "peer": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-gyp/node_modules/cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "optional": true, + "peer": true, + "dependencies": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/node-gyp/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-gyp/node_modules/make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "optional": true, + "peer": true, + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/node-gyp/node_modules/minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "optional": true, + "peer": true, + "dependencies": { + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "optionalDependencies": { + "encoding": "^0.1.12" + } + }, + "node_modules/node-gyp/node_modules/socks-proxy-agent": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", + "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "optional": true, + "peer": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/node-gyp/node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "optional": true, + "peer": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/node-gyp/node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "optional": true, + "peer": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/node-gyp/node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "optional": true, + "peer": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/node-gyp/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true, + "peer": true + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + }, + "node_modules/node-sass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-7.0.3.tgz", + "integrity": "sha512-8MIlsY/4dXUkJDYht9pIWBhMil3uHmE8b/AdJPjmFn1nBx9X9BASzfzmsCy0uCCb8eqI3SYYzVPDswWqSx7gjw==", + "hasInstallScript": true, + "optional": true, + "peer": true, + "dependencies": { + "async-foreach": "^0.1.3", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "gaze": "^1.0.0", + "get-stdin": "^4.0.1", + "glob": "^7.0.3", + "lodash": "^4.17.15", + "meow": "^9.0.0", + "nan": "^2.13.2", + "node-gyp": "^8.4.1", + "npmlog": "^5.0.0", + "request": "^2.88.0", + "sass-graph": "^4.0.1", + "stdout-stream": "^1.4.0", + "true-case-path": "^1.0.2" + }, + "bin": { + "node-sass": "bin/node-sass" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/node-sass/node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "optional": true, + "peer": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-sass/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "optional": true, + "peer": true, + "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/node-sass/node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "optional": true, + "peer": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-sass/node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "optional": true, + "peer": true, + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "optional": true, + "peer": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "optional": true, + "peer": true, + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "optional": true, + "peer": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nwsapi": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz", + "integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==", + "license": "MIT" + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "optional": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/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-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "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": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.6.tgz", + "integrity": "sha512-lq+61g26E/BgHv0ZTFgRvi7NMEPuAxLkFU7rukXjc/AlwH4Am5xXVnIXy3un1bg/JPbXHrixRkK1itUzzPiIjQ==", + "dependencies": { + "array.prototype.reduce": "^1.0.5", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.21.2", + "safe-array-concat": "^1.0.0" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", + "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1" + } + }, + "node_modules/object.hasown": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", + "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", + "dependencies": { + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.values": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_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" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optimism": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.16.2.tgz", + "integrity": "sha512-zWNbgWj+3vLEjZNIh/okkY2EUfX+vB9TJopzIZwT1xxaMqC5hRLLraePod4c5n4He08xuXNH+zhKFFCu390wiQ==", + "dependencies": { + "@wry/context": "^0.7.0", + "@wry/trie": "^0.3.0" + } + }, + "node_modules/optimism/node_modules/@wry/trie": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.3.2.tgz", + "integrity": "sha512-yRTyhWSls2OY/pYLfwff867r8ekooZ4UI+/gxot5Wj8EFwSf2rG+n+Mo/6LoLQm1TKA4GRj2+LCpbfS937dClQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "optional": true, + "peer": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry/node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "engines": { + "node": ">= 4" + } + }, + "node_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==", + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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/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/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "license": "MIT" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "license": "ISC" + }, + "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/jonschlinkert" + } + }, + "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==", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "engines": { + "node": ">=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==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-attribute-case-insensitive": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz", + "integrity": "sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-browser-comments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-4.0.0.tgz", + "integrity": "sha512-X9X9/WN3KIvY9+hNERUqX9gncsgBA25XaeR+jshHz2j8+sYyHktHw1JdKuMjeLpGktXidqDhA7b/qm1mrBDmgg==", + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "browserslist": ">=4", + "postcss": ">=8" + } + }, + "node_modules/postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "dependencies": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-clamp": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", + "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=7.6.0" + }, + "peerDependencies": { + "postcss": "^8.4.6" + } + }, + "node_modules/postcss-color-functional-notation": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", + "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-color-hex-alpha": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz", + "integrity": "sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-rebeccapurple": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz", + "integrity": "sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-colormin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-convert-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-custom-media": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz", + "integrity": "sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/postcss-custom-properties": { + "version": "12.1.11", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz", + "integrity": "sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-custom-selectors": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz", + "integrity": "sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==", + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/postcss-dir-pseudo-class": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz", + "integrity": "sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-discard-comments": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-empty": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-double-position-gradients": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz", + "integrity": "sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-env-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", + "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-flexbugs-fixes": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-5.0.2.tgz", + "integrity": "sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==", + "peerDependencies": { + "postcss": "^8.1.4" + } + }, + "node_modules/postcss-focus-visible": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", + "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-within": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", + "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-font-variant": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-gap-properties": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", + "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-image-set-function": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz", + "integrity": "sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/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": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-initial": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", + "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-lab-function": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz", + "integrity": "sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", + "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", + "dependencies": { + "lilconfig": "^2.0.5", + "yaml": "^2.1.1" + }, + "engines": { + "node": ">= 14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "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==", + "engines": { + "node": ">= 14" + } + }, + "node_modules/postcss-loader": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", + "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", + "dependencies": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.5" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-logical": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", + "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-media-minmax": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", + "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-rules": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "dependencies": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-params": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "dependencies": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "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": { + "generic-names": "^4.0.0", + "icss-utils": "^5.1.0", + "lodash.camelcase": "^4.3.0", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "string-hash": "^1.1.1" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", + "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-nested": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", + "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.11" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-nesting": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", + "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", + "dependencies": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-normalize": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize/-/postcss-normalize-10.0.1.tgz", + "integrity": "sha512-+5w18/rDev5mqERcG3W5GZNMJa1eoYYNGo8gB7tEwaos0ajk3ZXAI4mHGcNT47NE+ZnZD1pEpUOFLvltIwmeJA==", + "dependencies": { + "@csstools/normalize.css": "*", + "postcss-browser-comments": "^4", + "sanitize.css": "*" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "browserslist": ">= 4", + "postcss": ">= 8" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-string": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "dependencies": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-opacity-percentage": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.3.tgz", + "integrity": "sha512-An6Ba4pHBiDtyVpSLymUUERMo2cU7s+Obz6BTrS+gxkbnSBNKSuD0AVUc+CpBMrpVPKKfoVz0WQCX+Tnst0i4A==", + "funding": [ + { + "type": "kofi", + "url": "https://ko-fi.com/mrcgrtz" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/mrcgrtz" + } + ], + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-ordered-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "dependencies": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-overflow-shorthand": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", + "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-page-break": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "peerDependencies": { + "postcss": "^8" + } + }, + "node_modules/postcss-place": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", + "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-preset-env": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.8.3.tgz", + "integrity": "sha512-T1LgRm5uEVFSEF83vHZJV2z19lHg4yJuZ6gXZZkqVsqv63nlr6zabMH3l4Pc01FQCyfWVrh2GaUeCVy9Po+Aag==", + "dependencies": { + "@csstools/postcss-cascade-layers": "^1.1.1", + "@csstools/postcss-color-function": "^1.1.1", + "@csstools/postcss-font-format-keywords": "^1.0.1", + "@csstools/postcss-hwb-function": "^1.0.2", + "@csstools/postcss-ic-unit": "^1.0.1", + "@csstools/postcss-is-pseudo-class": "^2.0.7", + "@csstools/postcss-nested-calc": "^1.0.0", + "@csstools/postcss-normalize-display-values": "^1.0.1", + "@csstools/postcss-oklab-function": "^1.1.1", + "@csstools/postcss-progressive-custom-properties": "^1.3.0", + "@csstools/postcss-stepped-value-functions": "^1.0.1", + "@csstools/postcss-text-decoration-shorthand": "^1.0.0", + "@csstools/postcss-trigonometric-functions": "^1.0.2", + "@csstools/postcss-unset-value": "^1.0.2", + "autoprefixer": "^10.4.13", + "browserslist": "^4.21.4", + "css-blank-pseudo": "^3.0.3", + "css-has-pseudo": "^3.0.4", + "css-prefers-color-scheme": "^6.0.3", + "cssdb": "^7.1.0", + "postcss-attribute-case-insensitive": "^5.0.2", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^4.2.4", + "postcss-color-hex-alpha": "^8.0.4", + "postcss-color-rebeccapurple": "^7.1.1", + "postcss-custom-media": "^8.0.2", + "postcss-custom-properties": "^12.1.10", + "postcss-custom-selectors": "^6.0.3", + "postcss-dir-pseudo-class": "^6.0.5", + "postcss-double-position-gradients": "^3.1.2", + "postcss-env-function": "^4.0.6", + "postcss-focus-visible": "^6.0.4", + "postcss-focus-within": "^5.0.4", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^3.0.5", + "postcss-image-set-function": "^4.0.7", + "postcss-initial": "^4.0.1", + "postcss-lab-function": "^4.2.1", + "postcss-logical": "^5.0.4", + "postcss-media-minmax": "^5.0.0", + "postcss-nesting": "^10.2.0", + "postcss-opacity-percentage": "^1.1.2", + "postcss-overflow-shorthand": "^3.0.4", + "postcss-page-break": "^3.0.4", + "postcss-place": "^7.0.5", + "postcss-pseudo-class-any-link": "^7.1.6", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-pseudo-class-any-link": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", + "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-replace-overflow-wrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "peerDependencies": { + "postcss": "^8.0.3" + } + }, + "node_modules/postcss-selector-not": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz", + "integrity": "sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/postcss-svgo/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/postcss-svgo/node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/postcss-svgo/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/postcss-svgo/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/postcss-svgo/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/postcss-svgo/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/postcss-svgo/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "node_modules/postcss-svgo/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-svgo/node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/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/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" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-format": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "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": { + "@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.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/pretty-format/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "node_modules/process-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/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "dependencies": { + "asap": "~2.0.6" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "optional": true, + "peer": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "optional": true, + "peer": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "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": { + "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/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dev": true, + "dependencies": { + "escape-goat": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "license": "MIT" + }, + "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/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "optional": true, + "peer": true, + "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==", + "dependencies": { + "performance-now": "^2.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/randomatic": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", + "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", + "dependencies": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_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/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/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-app-polyfill": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz", + "integrity": "sha512-sZ41cxiU5llIB003yxxQBYrARBqe0repqPTTYBTmMqTz9szeBbE37BehCE891NZsmdZqqP+xWKdT3eo3vOzN8w==", + "dependencies": { + "core-js": "^3.19.2", + "object-assign": "^4.1.1", + "promise": "^8.1.0", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.9", + "whatwg-fetch": "^3.6.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/react-app-rewired": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/react-app-rewired/-/react-app-rewired-2.2.1.tgz", + "integrity": "sha512-uFQWTErXeLDrMzOJHKp0h8P1z0LV9HzPGsJ6adOtGlA/B9WfT6Shh4j2tLTTGlXOfiVx6w6iWpp7SOC5pvk+gA==", + "dependencies": { + "semver": "^5.6.0" + }, + "bin": { + "react-app-rewired": "bin/index.js" + }, + "peerDependencies": { + "react-scripts": ">=2.1.3" + } + }, + "node_modules/react-app-rewired/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/react-async-script": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/react-async-script/-/react-async-script-1.2.0.tgz", + "integrity": "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==", + "dependencies": { + "hoist-non-react-statics": "^3.3.0", + "prop-types": "^15.5.0" + }, + "peerDependencies": { + "react": ">=16.4.1" + } + }, + "node_modules/react-beautiful-dnd": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.1.tgz", + "integrity": "sha512-0Lvs4tq2VcrEjEgDXHjT98r+63drkKEgqyxdA7qD3mvKwga6a5SscbdLPO2IExotU1jW8L0Ksdl0Cj2AF67nPQ==", + "dependencies": { + "@babel/runtime": "^7.9.2", + "css-box-model": "^1.2.0", + "memoize-one": "^5.1.1", + "raf-schd": "^4.0.2", + "react-redux": "^7.2.0", + "redux": "^4.0.4", + "use-memo-one": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8.5 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.5 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-bootstrap": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.8.0.tgz", + "integrity": "sha512-e/aNtxl0Z2ozrIaR82jr6Zz7ss9GSoaXpQaxmvtDUsTZIq/XalkduR/ZXP6vbQHz2T4syvjA+4FbtwELxxmpww==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@restart/hooks": "^0.4.9", + "@restart/ui": "^1.6.3", + "@types/react-transition-group": "^4.4.5", + "classnames": "^2.3.2", + "dom-helpers": "^5.2.1", + "invariant": "^2.2.4", + "prop-types": "^15.8.1", + "prop-types-extra": "^1.1.0", + "react-transition-group": "^4.4.5", + "uncontrollable": "^7.2.1", + "warning": "^4.0.3" + }, + "peerDependencies": { + "@types/react": ">=16.14.8", + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-datepicker": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-7.3.0.tgz", + "integrity": "sha512-EqRKLAtLZUTztiq6a+tjSjQX9ES0Xd229JPckAtyZZ4GoY3rtvNWAzkYZnQUf6zTWT50Ki0+t+W9VRQIkSJLfg==", + "dependencies": { + "@floating-ui/react": "^0.26.2", + "clsx": "^2.1.0", + "date-fns": "^3.3.1", + "prop-types": "^15.7.2", + "react-onclickoutside": "^6.13.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17 || ^18", + "react-dom": "^16.9.0 || ^17 || ^18" + } + }, + "node_modules/react-datepicker/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/react-datepicker/node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/react-dev-utils": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", + "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", + "dependencies": { + "@babel/code-frame": "^7.16.0", + "address": "^1.1.2", + "browserslist": "^4.18.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "detect-port-alt": "^1.1.6", + "escape-string-regexp": "^4.0.0", + "filesize": "^8.0.6", + "find-up": "^5.0.0", + "fork-ts-checker-webpack-plugin": "^6.5.0", + "global-modules": "^2.0.0", + "globby": "^11.0.4", + "gzip-size": "^6.0.0", + "immer": "^9.0.7", + "is-root": "^2.1.0", + "loader-utils": "^3.2.0", + "open": "^8.4.0", + "pkg-up": "^3.1.0", + "prompts": "^2.4.2", + "react-error-overlay": "^6.0.11", + "recursive-readdir": "^2.2.2", + "shell-quote": "^1.7.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/react-dev-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/react-dev-utils/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dom": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + }, + "peerDependencies": { + "react": "17.0.2" + } + }, + "node_modules/react-error-overlay": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", + "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" + }, + "node_modules/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==", + "dev": true + }, + "node_modules/react-google-recaptcha": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-3.1.0.tgz", + "integrity": "sha512-cYW2/DWas8nEKZGD7SCu9BSuVz8iOcOLHChHyi7upUuVhkpkhYG/6N3KDiTQ3XAiZ2UAZkfvYKMfAHOzBOcGEg==", + "dependencies": { + "prop-types": "^15.5.0", + "react-async-script": "^1.2.0" + }, + "peerDependencies": { + "react": ">=16.4.1" + } + }, + "node_modules/react-i18next": { + "version": "11.18.6", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.18.6.tgz", + "integrity": "sha512-yHb2F9BiT0lqoQDt8loZ5gWP331GwctHz9tYQ8A2EIEUu+CcEdjBLQWli1USG3RdWQt3W+jqQLg/d4rrQR96LA==", + "dependencies": { + "@babel/runtime": "^7.14.5", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 19.0.0", + "react": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/react-icons": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.2.1.tgz", + "integrity": "sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==", + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-infinite-scroll-component": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-infinite-scroll-component/-/react-infinite-scroll-component-6.1.0.tgz", + "integrity": "sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ==", + "dependencies": { + "throttle-debounce": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.0.0" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" + }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "node_modules/react-multi-carousel": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/react-multi-carousel/-/react-multi-carousel-2.8.5.tgz", + "integrity": "sha512-C5DAvJkfzR2JK9YixZ3oyF9x6R4LW6nzTpIXrl9Oujxi4uqP9SzVVCjl+JLM3tSdqdjAx/oWZK3dTVBSR73Q+w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-onclickoutside": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.13.0.tgz", + "integrity": "sha512-ty8So6tcUpIb+ZE+1HAhbLROvAIJYyJe/1vRrrcmW+jLsaM+/powDRqxzo6hSh9CuRZGSL1Q8mvcF5WRD93a0A==", + "funding": { + "type": "individual", + "url": "https://github.com/Pomax/react-onclickoutside/blob/master/FUNDING.md" + }, + "peerDependencies": { + "react": "^15.5.x || ^16.x || ^17.x || ^18.x", + "react-dom": "^15.5.x || ^16.x || ^17.x || ^18.x" + } + }, + "node_modules/react-popper": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz", + "integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==", + "dev": true, + "dependencies": { + "react-fast-compare": "^3.0.1", + "warning": "^4.0.2" + }, + "peerDependencies": { + "@popperjs/core": "^2.0.0", + "react": "^16.8.0 || ^17 || ^18", + "react-dom": "^16.8.0 || ^17 || ^18" + } + }, + "node_modules/react-redux": { + "version": "7.2.9", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", + "integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==", + "dependencies": { + "@babel/runtime": "^7.15.4", + "@types/react-redux": "^7.1.20", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^17.0.2" + }, + "peerDependencies": { + "react": "^16.8.3 || ^17 || ^18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/react-redux/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "node_modules/react-refresh": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", + "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "6.25.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.25.1.tgz", + "integrity": "sha512-u8ELFr5Z6g02nUtpPAggP73Jigj1mRePSwhS/2nkTrlPU5yEkH1vYzWNyvSnSzeeE2DNqWdH+P8OhIh9wuXhTw==", + "dependencies": { + "@remix-run/router": "1.18.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.25.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.25.1.tgz", + "integrity": "sha512-0tUDpbFvk35iv+N89dWNrJp+afLgd+y4VtorJZuOCXK0kkCWjEvb3vTJM++SYvMEpbVwXKf3FjeVveVEb6JpDQ==", + "dependencies": { + "@remix-run/router": "1.18.0", + "react-router": "6.25.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-scripts": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", + "integrity": "sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==", + "dependencies": { + "@babel/core": "^7.16.0", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", + "@svgr/webpack": "^5.5.0", + "babel-jest": "^27.4.2", + "babel-loader": "^8.2.3", + "babel-plugin-named-asset-import": "^0.3.8", + "babel-preset-react-app": "^10.0.1", + "bfj": "^7.0.2", + "browserslist": "^4.18.1", + "camelcase": "^6.2.1", + "case-sensitive-paths-webpack-plugin": "^2.4.0", + "css-loader": "^6.5.1", + "css-minimizer-webpack-plugin": "^3.2.0", + "dotenv": "^10.0.0", + "dotenv-expand": "^5.1.0", + "eslint": "^8.3.0", + "eslint-config-react-app": "^7.0.1", + "eslint-webpack-plugin": "^3.1.1", + "file-loader": "^6.2.0", + "fs-extra": "^10.0.0", + "html-webpack-plugin": "^5.5.0", + "identity-obj-proxy": "^3.0.0", + "jest": "^27.4.3", + "jest-resolve": "^27.4.2", + "jest-watch-typeahead": "^1.0.0", + "mini-css-extract-plugin": "^2.4.5", + "postcss": "^8.4.4", + "postcss-flexbugs-fixes": "^5.0.2", + "postcss-loader": "^6.2.1", + "postcss-normalize": "^10.0.1", + "postcss-preset-env": "^7.0.1", + "prompts": "^2.4.2", + "react-app-polyfill": "^3.0.0", + "react-dev-utils": "^12.0.1", + "react-refresh": "^0.11.0", + "resolve": "^1.20.0", + "resolve-url-loader": "^4.0.0", + "sass-loader": "^12.3.0", + "semver": "^7.3.5", + "source-map-loader": "^3.0.0", + "style-loader": "^3.3.1", + "tailwindcss": "^3.0.2", + "terser-webpack-plugin": "^5.2.5", + "webpack": "^5.64.4", + "webpack-dev-server": "^4.6.0", + "webpack-manifest-plugin": "^4.0.2", + "workbox-webpack-plugin": "^6.4.1" + }, + "bin": { + "react-scripts": "bin/react-scripts.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + }, + "peerDependencies": { + "react": ">= 16", + "typescript": "^3.2.1 || ^4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/react-scripts/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==", + "license": "MIT", + "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" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/react-scripts/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==", + "license": "MIT", + "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" + }, + "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/react-scripts/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==", + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/react-scripts/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==", + "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" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/react-scripts/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==", + "license": "MIT", + "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/react-scripts/node_modules/@jest/reporters": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "license": "MIT", + "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/react-scripts/node_modules/@jest/schemas": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.24.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/react-scripts/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==", + "license": "MIT", + "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/react-scripts/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==", + "license": "MIT", + "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/react-scripts/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==", + "license": "MIT", + "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/react-scripts/node_modules/@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "license": "MIT" + }, + "node_modules/react-scripts/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==", + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/react-scripts/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==", + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/react-scripts/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/react-scripts/node_modules/babel-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "dependencies": { + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/react-scripts/node_modules/babel-plugin-jest-hoist": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/react-scripts/node_modules/babel-preset-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "dependencies": { + "babel-plugin-jest-hoist": "^27.5.1", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/react-scripts/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-scripts/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/react-scripts/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==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/react-scripts/node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "license": "MIT" + }, + "node_modules/react-scripts/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==", + "license": "MIT", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/react-scripts/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==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/react-scripts/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==", + "license": "MIT", + "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" + } + }, + "node_modules/react-scripts/node_modules/jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", + "license": "MIT", + "dependencies": { + "@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/react-scripts/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==", + "license": "MIT", + "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/react-scripts/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==", + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/react-scripts/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==", + "license": "MIT", + "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" + }, + "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/react-scripts/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==", + "license": "MIT", + "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": "^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/react-scripts/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==", + "license": "MIT", + "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/react-scripts/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==", + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/react-scripts/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==", + "license": "MIT", + "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" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/react-scripts/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==", + "license": "MIT", + "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" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/react-scripts/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==", + "license": "MIT", + "dependencies": { + "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/react-scripts/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==", + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^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/react-scripts/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==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/react-scripts/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==", + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/react-scripts/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==", + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "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" + } + }, + "node_modules/react-scripts/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==", + "license": "MIT", + "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_modules/react-scripts/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==", + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/react-scripts/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==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.5.1", + "semver": "^7.3.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/react-scripts/node_modules/jest-watch-typeahead": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-1.1.0.tgz", + "integrity": "sha512-Va5nLSJTN7YFtC2jd+7wsoe1pNe5K4ShLux/E5iHEwlB9AxaxmggY7to9KUqKojhaJw3aXqt5WAb4jGPOolpEw==", + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.3.1", + "chalk": "^4.0.0", + "jest-regex-util": "^28.0.0", + "jest-watcher": "^28.0.0", + "slash": "^4.0.0", + "string-length": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "jest": "^27.0.0 || ^28.0.0" + } + }, + "node_modules/react-scripts/node_modules/jest-watch-typeahead/node_modules/@jest/console": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", + "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/react-scripts/node_modules/jest-watch-typeahead/node_modules/@jest/console/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-scripts/node_modules/jest-watch-typeahead/node_modules/@jest/test-result": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", + "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", + "license": "MIT", + "dependencies": { + "@jest/console": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/react-scripts/node_modules/jest-watch-typeahead/node_modules/@jest/types": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/react-scripts/node_modules/jest-watch-typeahead/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==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/react-scripts/node_modules/jest-watch-typeahead/node_modules/emittery": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/react-scripts/node_modules/jest-watch-typeahead/node_modules/jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/react-scripts/node_modules/jest-watch-typeahead/node_modules/jest-message-util/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-scripts/node_modules/jest-watch-typeahead/node_modules/jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "license": "MIT", + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/react-scripts/node_modules/jest-watch-typeahead/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "license": "MIT", + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/react-scripts/node_modules/jest-watch-typeahead/node_modules/jest-watcher": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", + "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", + "license": "MIT", + "dependencies": { + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^28.1.3", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/react-scripts/node_modules/jest-watch-typeahead/node_modules/jest-watcher/node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/react-scripts/node_modules/jest-watch-typeahead/node_modules/jest-watcher/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-scripts/node_modules/jest-watch-typeahead/node_modules/pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/react-scripts/node_modules/jest-watch-typeahead/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/react-scripts/node_modules/jest-watch-typeahead/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-scripts/node_modules/jest-watch-typeahead/node_modules/string-length": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-5.0.1.tgz", + "integrity": "sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==", + "license": "MIT", + "dependencies": { + "char-regex": "^2.0.0", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-scripts/node_modules/jest-watch-typeahead/node_modules/string-length/node_modules/char-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.1.tgz", + "integrity": "sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw==", + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/react-scripts/node_modules/jest-watch-typeahead/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/react-scripts/node_modules/jest-watch-typeahead/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/react-scripts/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==", + "license": "MIT", + "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/react-scripts/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==", + "license": "MIT", + "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/react-scripts/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==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/react-scripts/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==", + "license": "MIT" + }, + "node_modules/react-scripts/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==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-scripts/node_modules/v8-to-istanbul": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "license": "ISC", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/react-scripts/node_modules/v8-to-istanbul/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/react-scripts/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/react-toastify": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.3.tgz", + "integrity": "sha512-fPfb8ghtn/XMxw3LkxQBk3IyagNpF/LIKjOBflbexr2AWxAH1MJgvnESwEwBn9liLFXgTKWgBSdZpw9m4OTHTg==", + "dependencies": { + "clsx": "^1.1.1" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, + "node_modules/react-tooltip": { + "version": "5.27.1", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.27.1.tgz", + "integrity": "sha512-a+micPXcMOMt11CYlwJD4XShcqGziasHco4NPe1OFw298WBTILMyzUgNC1LAFViAe791JdHNVSJIpzhZm2MvDA==", + "dependencies": { + "@floating-ui/dom": "^1.6.1", + "classnames": "^2.3.0" + }, + "peerDependencies": { + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "optional": true, + "peer": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "optional": true, + "peer": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "optional": true, + "peer": true + }, + "node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "optional": true, + "peer": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/read-pkg/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "optional": true, + "peer": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dependencies": { + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "devOptional": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/redux-thunk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", + "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", + "peerDependencies": { + "redux": "^4" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/registry-auth-token": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", + "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", + "dev": true, + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remarkable": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/remarkable/-/remarkable-1.7.4.tgz", + "integrity": "sha512-e6NKUXgX95whv7IgddywbeN/ItCkWbISmc2DiqHJb0wTrqZIexqdco5b8Z3XZoo/48IdNVKM9ZCvTPJ4F5uvhg==", + "dependencies": { + "argparse": "^1.0.10", + "autolinker": "~0.28.0" + }, + "bin": { + "remarkable": "bin/remarkable.js" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/renderkid/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/renderkid/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "optional": true, + "peer": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "optional": true, + "peer": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request/node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "optional": true, + "peer": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "optional": true, + "peer": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/reselect": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", + "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-dir/node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-dir/node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-dir/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/resolve-url-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz", + "integrity": "sha512-05VEMczVREcbtT7Bz+C+96eUO5HDNvdthIiMB34t7FcF8ehcu4wC0sSgPUubs3XW2Q3CNLJk/BJrCU9wVRymiA==", + "dependencies": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^7.0.35", + "source-map": "0.6.1" + }, + "engines": { + "node": ">=8.9" + }, + "peerDependencies": { + "rework": "1.0.1", + "rework-visit": "1.0.0" + }, + "peerDependenciesMeta": { + "rework": { + "optional": true + }, + "rework-visit": { + "optional": true + } + } + }, + "node_modules/resolve-url-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/resolve-url-loader/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" + }, + "node_modules/resolve-url-loader/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/resolve-url-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve.exports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz", + "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/response-iterator": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/response-iterator/-/response-iterator-0.2.6.tgz", + "integrity": "sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", + "dev": true, + "dependencies": { + "lowercase-keys": "^1.0.0" + } + }, + "node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restructure": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.0.tgz", + "integrity": "sha512-Xj8/MEIhhfj9X2rmD9iJ4Gga9EFqVlpMj3vfLnV2r/Mh5jRMryNV+6lWh9GdJtDBcBSPIqzRdfBQ3wDtNFv/uw==" + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "optional": true, + "peer": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", + "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", + "dev": true + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + }, + "node_modules/rollup": { + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-terser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", + "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0" + } + }, + "node_modules/rollup-plugin-terser/node_modules/jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/rollup-plugin-terser/node_modules/serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sanitize-html": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.13.0.tgz", + "integrity": "sha512-Xff91Z+4Mz5QiNSLdLWwjgBDm5b1RU6xBT0+12rapjiaR7SwfRdjw8f+6Rir2MXKLrDicRFHdb51hGOAxmsUIA==", + "dependencies": { + "deepmerge": "^4.2.2", + "escape-string-regexp": "^4.0.0", + "htmlparser2": "^8.0.0", + "is-plain-object": "^5.0.0", + "parse-srcset": "^1.0.2", + "postcss": "^8.3.11" + } + }, + "node_modules/sanitize-html/node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sanitize.css": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", + "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==" + }, + "node_modules/sass": { + "version": "1.77.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.4.tgz", + "integrity": "sha512-vcF3Ckow6g939GMA4PeU7b2K/9FALXk2KF9J87txdHzXbUF9XRQRwSxcAs/fGaTnJeBFd7UoV22j3lzMLdM0Pw==", + "devOptional": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-graph": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-4.0.1.tgz", + "integrity": "sha512-5YCfmGBmxoIRYHnKK2AKzrAkCoQ8ozO+iumT8K4tXJXRVCPf+7s1/9KxTSW3Rbvf+7Y7b4FR3mWyLnQr3PHocA==", + "optional": true, + "peer": true, + "dependencies": { + "glob": "^7.0.0", + "lodash": "^4.17.11", + "scss-tokenizer": "^0.4.3", + "yargs": "^17.2.1" + }, + "bin": { + "sassgraph": "bin/sassgraph" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/sass-loader": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", + "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", + "dependencies": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + } + } + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "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/schema-utils/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/scss-tokenizer": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.4.3.tgz", + "integrity": "sha512-raKLgf1LI5QMQnG+RxHz6oK0sL3x3I4FN2UDLqgLOGO8hodECNnNh5BXn7fAyBxrA8zVzdQizQ6XjNJQ+uBwMw==", + "optional": true, + "peer": true, + "dependencies": { + "js-base64": "^2.4.9", + "source-map": "^0.7.3" + } + }, + "node_modules/scss-tokenizer/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "optional": true, + "peer": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" + }, + "node_modules/selfsigned": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "dependencies": { + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "dependencies": { + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semver-diff/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "optional": true, + "peer": true + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-getter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.1.tgz", + "integrity": "sha512-9sVWOy+gthr+0G9DzqqLaYNA7+5OKkSmcqjL9cBpDEaZrr3ShQlyX2cZ/O/ozE41oxn/Tt0LGEM/w4Rub3A3gw==", + "dependencies": { + "to-object-path": "^0.3.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/shiki": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.10.3.tgz", + "integrity": "sha512-eneCLncGuvPdTutJuLyUGS8QNPAVFO5Trvld2wgEq1e002mwctAhJKeMGWtWVXOIEzmlcLRqcgPSorR6AVzOmQ==", + "peer": true, + "dependencies": { + "@shikijs/core": "1.10.3", + "@types/hast": "^3.0.4" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/sirv": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz", + "integrity": "sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==", + "dev": true, + "dependencies": { + "@polka/url": "^1.0.0-next.20", + "mrmime": "^1.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/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" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "optional": true, + "peer": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "optional": true, + "peer": true, + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.2.tgz", + "integrity": "sha512-BokxPoLjyl3iOrgkWaakaxqnelAJSS+0V+De0kKIq6lyWrXuiPgYTGp6z3iHmqljKAaLXwZa+ctD8GccRJeVvg==", + "dependencies": { + "abab": "^2.0.5", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead" + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "optional": true, + "peer": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "optional": true, + "peer": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "optional": true, + "peer": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", + "optional": true, + "peer": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "node_modules/sshpk": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "optional": true, + "peer": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==" + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stdout-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", + "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", + "optional": true, + "peer": true, + "dependencies": { + "readable-stream": "^2.0.1" + } + }, + "node_modules/stdout-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "optional": true, + "peer": true + }, + "node_modules/stdout-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "optional": true, + "peer": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/stdout-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "optional": true, + "peer": true + }, + "node_modules/stdout-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "optional": true, + "peer": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", + "integrity": "sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==", + "dev": true + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-natural-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", + "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "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.prototype.matchall": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/stringify-object/node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "engines": { + "node": ">=0.10.0" + } + }, + "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-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-color": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/strip-color/-/strip-color-0.1.0.tgz", + "integrity": "sha512-p9LsUieSjWNNAxVCXLeilaDlmuUOrDS5/dF9znM1nZc7EGX5+zEFC0bEevsNIaldjlks+2jns5Siz6F9iK6jwA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", + "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "devOptional": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-loader": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.3.tgz", + "integrity": "sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw==", + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, + "node_modules/sucrase": { + "version": "3.33.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.33.0.tgz", + "integrity": "sha512-ARGC7vbufOHfpvyGcZZXFaXCMZ9A4fffOGC5ucOW7+WHDGlAe8LJdf3Jts1sWhDeiI1RSWrKy5Hodl+JWGdW2A==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "7.1.6", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" + }, + "node_modules/svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "deprecated": "This SVGO version is no longer supported. Upgrade to v2.x.x.", + "dependencies": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/svgo/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/svgo/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/svgo/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/svgo/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/svgo/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/svgo/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/svgo/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/svgo/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "license": "MIT" + }, + "node_modules/synckit": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" + }, + "node_modules/tailwindcss": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz", + "integrity": "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.18.2", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tailwindcss/node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.1.15", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", + "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", + "optional": true, + "peer": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true, + "peer": true + }, + "node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/tempy": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", + "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", + "dependencies": { + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.0.tgz", + "integrity": "sha512-JpcpGOQLOXm2jsomozdMDpd5f8ZHh1rR48OFgWUH3QsyZcfPgv2qDCYbcDEAYNd4OZRj2bWYKpwdll/udZCk/Q==", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/throat": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz", + "integrity": "sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==", + "license": "MIT" + }, + "node_modules/throttle-debounce": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-2.3.0.tgz", + "integrity": "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==", + "engines": { + "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", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/through2/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/through2/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/through2/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/through2/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/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "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/tmp-promise/node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-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/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/toml": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/toml/-/toml-2.3.6.tgz", + "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.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "license": "BSD-3-Clause", + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/true-case-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", + "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", + "optional": true, + "peer": true, + "dependencies": { + "glob": "^7.1.2" + } + }, + "node_modules/tryer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", + "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==" + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" + }, + "node_modules/ts-invariant": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.10.3.tgz", + "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==", + "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==", + "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==", + "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/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/tsx": { + "version": "4.16.2", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.16.2.tgz", + "integrity": "sha512-C1uWweJDgdtX2x600HjaFaucXTilT7tgUZHbOE4+ypskZ1OP8CRCSDkCxG6Vya9EwaFIVagWwpaVAn5wzypaqQ==", + "dev": true, + "dependencies": { + "esbuild": "~0.21.5", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "optional": true, + "peer": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "optional": true, + "peer": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typedoc": { + "version": "0.26.3", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.26.3.tgz", + "integrity": "sha512-6d2Sw9disvvpdk4K7VNjKr5/3hzijtfQVHRthhDqJgnhMHy1wQz4yPMJVKXElvnZhFr0nkzo+GzjXDTRV5yLpg==", + "peer": true, + "dependencies": { + "lunr": "^2.3.9", + "markdown-it": "^14.1.0", + "minimatch": "^9.0.5", + "shiki": "^1.9.1", + "yaml": "^2.4.5" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x" + } + }, + "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==", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "typedoc": "0.26.x" + } + }, + "node_modules/typedoc/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/typedoc/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "peer": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typedoc/node_modules/yaml": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", + "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "peer": true + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/uncontrollable": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", + "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", + "dependencies": { + "@babel/runtime": "^7.6.3", + "@types/react": ">=16.9.11", + "invariant": "^2.2.4", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": ">=15.0.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-properties": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", + "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", + "dependencies": { + "base64-js": "^1.3.0", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "dependencies": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } + }, + "node_modules/unicode-trie/node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==" + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg==" + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/update-notifier": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", + "dev": true, + "dependencies": { + "boxen": "^5.0.0", + "chalk": "^4.1.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^5.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.1.0", + "pupa": "^2.1.1", + "semver": "^7.3.4", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/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/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", + "dev": true, + "dependencies": { + "prepend-http": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/use-memo-one": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz", + "integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/util.promisify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", + "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/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==", + "license": "MIT" + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "optional": true, + "peer": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "engines": [ + "node >=0.6.0" + ], + "optional": true, + "peer": true, + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/verror/node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "optional": true, + "peer": true + }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", + "license": "MIT", + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "license": "MIT", + "dependencies": { + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/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.2", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.2.tgz", + "integrity": "sha512-nYfoOqb4EmElljyXU2qdeE76KsvoHdftQKY4DzA9Aw8DervCg2bG634pHLrJ/d6+B4mE3nWTSJv8Mo7B2mbZkw==" + }, + "node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=10.4" + } + }, + "node_modules/webpack": { + "version": "5.88.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.1.tgz", + "integrity": "sha512-FROX3TxQnC/ox4N+3xQoWZzvGXSuscxR32rbzjpXgEzWudJFEJBpdlkkob2ylrv5yzzufD1zph1OoFsLtm6stQ==", + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", + "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-manifest-plugin": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-4.1.1.tgz", + "integrity": "sha512-YXUAwxtfKIJIKkhg03MKuiFAD72PlrqCiwdwO4VEXdRO5V0ORCNwaOwAZawPZalCbmH9kBDmXnNeQOw+BIEiow==", + "dependencies": { + "tapable": "^2.0.0", + "webpack-sources": "^2.2.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "peerDependencies": { + "webpack": "^4.44.2 || ^5.47.0" + } + }, + "node_modules/webpack-manifest-plugin/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-manifest-plugin/node_modules/webpack-sources": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.1.tgz", + "integrity": "sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==", + "dependencies": { + "source-list-map": "^2.0.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "license": "MIT", + "dependencies": { + "iconv-lite": "0.4.24" + } + }, + "node_modules/whatwg-encoding/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": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-fetch": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", + "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "license": "MIT" + }, + "node_modules/whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "license": "MIT", + "dependencies": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "optional": true, + "peer": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/workbox-background-sync": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-6.6.0.tgz", + "integrity": "sha512-jkf4ZdgOJxC9u2vztxLuPT/UjlH7m/nWRQ/MgGL0v8BJHoZdVGJd18Kck+a0e55wGXdqyHO+4IQTk0685g4MUw==", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-broadcast-update": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-6.6.0.tgz", + "integrity": "sha512-nm+v6QmrIFaB/yokJmQ/93qIJ7n72NICxIwQwe5xsZiV2aI93MGGyEyzOzDPVz5THEr5rC3FJSsO3346cId64Q==", + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-build": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-6.6.0.tgz", + "integrity": "sha512-Tjf+gBwOTuGyZwMz2Nk/B13Fuyeo0Q84W++bebbVsfr9iLkDSo6j6PST8tET9HYA58mlRXwlMGpyWO8ETJiXdQ==", + "dependencies": { + "@apideck/better-ajv-errors": "^0.3.1", + "@babel/core": "^7.11.1", + "@babel/preset-env": "^7.11.0", + "@babel/runtime": "^7.11.2", + "@rollup/plugin-babel": "^5.2.0", + "@rollup/plugin-node-resolve": "^11.2.1", + "@rollup/plugin-replace": "^2.4.1", + "@surma/rollup-plugin-off-main-thread": "^2.2.3", + "ajv": "^8.6.0", + "common-tags": "^1.8.0", + "fast-json-stable-stringify": "^2.1.0", + "fs-extra": "^9.0.1", + "glob": "^7.1.6", + "lodash": "^4.17.20", + "pretty-bytes": "^5.3.0", + "rollup": "^2.43.1", + "rollup-plugin-terser": "^7.0.0", + "source-map": "^0.8.0-beta.0", + "stringify-object": "^3.3.0", + "strip-comments": "^2.0.1", + "tempy": "^0.6.0", + "upath": "^1.2.0", + "workbox-background-sync": "6.6.0", + "workbox-broadcast-update": "6.6.0", + "workbox-cacheable-response": "6.6.0", + "workbox-core": "6.6.0", + "workbox-expiration": "6.6.0", + "workbox-google-analytics": "6.6.0", + "workbox-navigation-preload": "6.6.0", + "workbox-precaching": "6.6.0", + "workbox-range-requests": "6.6.0", + "workbox-recipes": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0", + "workbox-streams": "6.6.0", + "workbox-sw": "6.6.0", + "workbox-window": "6.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/workbox-build/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/workbox-build/node_modules/source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "dependencies": { + "whatwg-url": "^7.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/workbox-build/node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/workbox-build/node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, + "node_modules/workbox-build/node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "node_modules/workbox-cacheable-response": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-6.6.0.tgz", + "integrity": "sha512-JfhJUSQDwsF1Xv3EV1vWzSsCOZn4mQ38bWEBR3LdvOxSPgB65gAM6cS2CX8rkkKHRgiLrN7Wxoyu+TuH67kHrw==", + "deprecated": "workbox-background-sync@6.6.0", + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-core": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.6.0.tgz", + "integrity": "sha512-GDtFRF7Yg3DD859PMbPAYPeJyg5gJYXuBQAC+wyrWuuXgpfoOrIQIvFRZnQ7+czTIQjIr1DhLEGFzZanAT/3bQ==" + }, + "node_modules/workbox-expiration": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-6.6.0.tgz", + "integrity": "sha512-baplYXcDHbe8vAo7GYvyAmlS4f6998Jff513L4XvlzAOxcl8F620O91guoJ5EOf5qeXG4cGdNZHkkVAPouFCpw==", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-google-analytics": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-6.6.0.tgz", + "integrity": "sha512-p4DJa6OldXWd6M9zRl0H6vB9lkrmqYFkRQ2xEiNdBFp9U0LhsGO7hsBscVEyH9H2/3eZZt8c97NB2FD9U2NJ+Q==", + "dependencies": { + "workbox-background-sync": "6.6.0", + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" + } + }, + "node_modules/workbox-navigation-preload": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-6.6.0.tgz", + "integrity": "sha512-utNEWG+uOfXdaZmvhshrh7KzhDu/1iMHyQOV6Aqup8Mm78D286ugu5k9MFD9SzBT5TcwgwSORVvInaXWbvKz9Q==", + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-precaching": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-6.6.0.tgz", + "integrity": "sha512-eYu/7MqtRZN1IDttl/UQcSZFkHP7dnvr/X3Vn6Iw6OsPMruQHiVjjomDFCNtd8k2RdjLs0xiz9nq+t3YVBcWPw==", + "dependencies": { + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" + } + }, + "node_modules/workbox-range-requests": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-6.6.0.tgz", + "integrity": "sha512-V3aICz5fLGq5DpSYEU8LxeXvsT//mRWzKrfBOIxzIdQnV/Wj7R+LyJVTczi4CQ4NwKhAaBVaSujI1cEjXW+hTw==", + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-recipes": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-6.6.0.tgz", + "integrity": "sha512-TFi3kTgYw73t5tg73yPVqQC8QQjxJSeqjXRO4ouE/CeypmP2O/xqmB/ZFBBQazLTPxILUQ0b8aeh0IuxVn9a6A==", + "dependencies": { + "workbox-cacheable-response": "6.6.0", + "workbox-core": "6.6.0", + "workbox-expiration": "6.6.0", + "workbox-precaching": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" + } + }, + "node_modules/workbox-routing": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.6.0.tgz", + "integrity": "sha512-x8gdN7VDBiLC03izAZRfU+WKUXJnbqt6PG9Uh0XuPRzJPpZGLKce/FkOX95dWHRpOHWLEq8RXzjW0O+POSkKvw==", + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-strategies": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.6.0.tgz", + "integrity": "sha512-eC07XGuINAKUWDnZeIPdRdVja4JQtTuc35TZ8SwMb1ztjp7Ddq2CJ4yqLvWzFWGlYI7CG/YGqaETntTxBGdKgQ==", + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-streams": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-6.6.0.tgz", + "integrity": "sha512-rfMJLVvwuED09CnH1RnIep7L9+mj4ufkTyDPVaXPKlhi9+0czCu+SJggWCIFbPpJaAZmp2iyVGLqS3RUmY3fxg==", + "dependencies": { + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0" + } + }, + "node_modules/workbox-sw": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-6.6.0.tgz", + "integrity": "sha512-R2IkwDokbtHUE4Kus8pKO5+VkPHD2oqTgl+XJwh4zbF1HyjAbgNmK/FneZHVU7p03XUt9ICfuGDYISWG9qV/CQ==" + }, + "node_modules/workbox-webpack-plugin": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-6.6.0.tgz", + "integrity": "sha512-xNZIZHalboZU66Wa7x1YkjIqEy1gTR+zPM+kjrYJzqN7iurYZBctBLISyScjhkJKYuRrZUP0iqViZTh8rS0+3A==", + "dependencies": { + "fast-json-stable-stringify": "^2.1.0", + "pretty-bytes": "^5.4.1", + "upath": "^1.2.0", + "webpack-sources": "^1.4.3", + "workbox-build": "6.6.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "webpack": "^4.4.0 || ^5.9.0" + } + }, + "node_modules/workbox-webpack-plugin/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workbox-webpack-plugin/node_modules/webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dependencies": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "node_modules/workbox-window": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-6.6.0.tgz", + "integrity": "sha512-L4N9+vka17d16geaJXXRjENLFldvkWy7JyGxElRD0JvBxvFEd8LOhr+uXCcar/NzAmIBRv9EZ+M+Qr4mOoBITw==", + "dependencies": { + "@types/trusted-types": "^2.0.2", + "workbox-core": "6.6.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "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/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "license": "Apache-2.0" + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "license": "MIT" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "engines": { + "node": ">=10" + }, + "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", + "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==" + }, + "node_modules/zen-observable-ts": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.2.5.tgz", + "integrity": "sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg==", + "dependencies": { + "zen-observable": "0.8.15" + } + }, + "node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + }, + "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==" + }, + "@adobe/css-tools": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.3.tgz", + "integrity": "sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==", + "dev": true + }, + "@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==" + }, + "@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@apideck/better-ajv-errors": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz", + "integrity": "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==", + "requires": { + "json-schema": "^0.4.0", + "jsonpointer": "^5.0.0", + "leven": "^3.1.0" + } + }, + "@apollo/client": { + "version": "3.7.17", + "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.7.17.tgz", + "integrity": "sha512-0EErSHEtKPNl5wgWikHJbKFAzJ/k11O0WO2QyqZSHpdxdAnw7UWHY4YiLbHCFG7lhrD+NTQ3Z/H9Jn4rcikoJA==", + "requires": { + "@graphql-typed-document-node/core": "^3.1.1", + "@wry/context": "^0.7.0", + "@wry/equality": "^0.5.0", + "@wry/trie": "^0.4.0", + "graphql-tag": "^2.12.6", + "hoist-non-react-statics": "^3.3.2", + "optimism": "^0.16.2", + "prop-types": "^15.7.2", + "response-iterator": "^0.2.6", + "symbol-observable": "^4.0.0", + "ts-invariant": "^0.10.3", + "tslib": "^2.3.0", + "zen-observable-ts": "^1.2.5" + } + }, + "@apollo/link-error": { + "version": "2.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@apollo/link-error/-/link-error-2.0.0-beta.3.tgz", + "integrity": "sha512-blNBBi9+4SEfb4Bhn8cYqGFhb0C7MjqLiRwNdUqwGefl1w+G8Ze8pCLHAyPxXLcslirtht9LY0i6ZOpCzSXHCg==", + "requires": { + "@apollo/client": "^3.0.0-beta.23", + "tslib": "^1.9.3" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "@apollo/react-testing": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@apollo/react-testing/-/react-testing-4.0.0.tgz", + "integrity": "sha512-P7Z/flUHpRRZYc3FkIqxZH9XD3FuP2Sgks1IXqGq2Zb7qI0aaTfVeRsLYmZNUcFOh2pTHxs0NXgPnH1VfYOpig==", + "requires": { + "@apollo/client": "latest" + } + }, + "@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "requires": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + } + }, + "@babel/compat-data": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz", + "integrity": "sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==" + }, + "@babel/core": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "dependencies": { + "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==" + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/eslint-parser": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.22.9.tgz", + "integrity": "sha512-xdMkt39/nviO/4vpVdrEYPwXCsYIXSSAr6mC7WQsNIlGnuxKyKE7GZjalcnbSWiC4OXGNNN3UQPeHfjSC6sTDA==", + "requires": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/generator": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", + "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", + "requires": { + "@babel/types": "^7.25.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@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==", + "requires": { + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.23.10", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.10.tgz", + "integrity": "sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.1.tgz", + "integrity": "sha512-kX4oXixDxG197yhX+J3Wp+NpL2wuCFjWQAr6yX2jtCnflK9ulMI51ULFGIrWiX1jGfvAxdHp+XQCcP2bZGPs9A==", + "requires": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==" + }, + "@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "requires": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "requires": { + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "requires": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + } + }, + "@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==", + "requires": { + "@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-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + } + }, + "@babel/helper-replace-supers": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", + "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5" + } + }, + "@babel/helper-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==", + "requires": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==" + }, + "@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==" + }, + "@babel/helper-validator-option": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==" + }, + "@babel/helper-wrap-function": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "requires": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + } + }, + "@babel/helpers": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz", + "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==", + "requires": { + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.0" + } + }, + "@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "requires": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "dependencies": { + "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==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "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==" + }, + "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==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.0.tgz", + "integrity": "sha512-CzdIU9jdP0dg7HdyB+bHvDJGagUv+qtzZt5rYCWwW6tITNqV9odjp6Qu41gkG0ca5UfdDUWrKkiAnHHdGRnOrA==" + }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz", + "integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz", + "integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.23.3" + } + }, + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.7.tgz", + "integrity": "sha512-LlRT7HgaifEpQA1ZgLVOIJZZFVPWN5iReq/7/JixwBtwcoeVGDBD53ZV28rrsLYOZs1Y/EHhA8N/Z6aazHR8cw==", + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-decorators": { + "version": "7.22.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.22.7.tgz", + "integrity": "sha512-omXqPF7Onq4Bb7wHxXjM3jSMSJvUUbvDvmmds7KI5n9Cq6Ln5I05I1W2nRlRof1rGdiUxJrxwe285WF96XlBXQ==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/plugin-syntax-decorators": "^7.22.5" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", + "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz", + "integrity": "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@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==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-decorators": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.22.5.tgz", + "integrity": "sha512-avpUOBS7IU6al8MmF1XpAyj9QYeLPuSDJI5D4pVMSMdL7xQokKqJPYQC67RCT0aCTashUXPiGwMJ0DEXXCEmMA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@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==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-flow": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.22.5.tgz", + "integrity": "sha512-9RdCl0i+q0QExayk2nOS7853w08yLucnnPML6EN9S8fgMPVtdLDCdx/cOQ/i44Lb9UeQX9A35yaqBBOMMZxPxQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz", + "integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-import-attributes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz", + "integrity": "sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", + "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", + "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", + "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-async-generator-functions": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.9.tgz", + "integrity": "sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ==", + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", + "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", + "requires": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", + "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz", + "integrity": "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-class-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz", + "integrity": "sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-class-static-block": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.4.tgz", + "integrity": "sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.8.tgz", + "integrity": "sha512-yAYslGsY1bX6Knmg46RjiCiNSwJKv2IUC8qOdYKqMMr0491SXFhcHqOdRDeCRohOOIzwN/90C6mQ9qAKgrP7dg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", + "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.15" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", + "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz", + "integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz", + "integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-dynamic-import": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.4.tgz", + "integrity": "sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", + "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-export-namespace-from": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz", + "integrity": "sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-transform-flow-strip-types": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.22.5.tgz", + "integrity": "sha512-tujNbZdxdG0/54g/oua8ISToaXTFBf8EnSb5PgQSciIXWOWKX3S4+JR7ZE9ol8FZwf9kxitzkGQ+QWeov/mCiA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-flow": "^7.22.5" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.6.tgz", + "integrity": "sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz", + "integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==", + "requires": { + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-json-strings": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.4.tgz", + "integrity": "sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", + "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-logical-assignment-operators": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.4.tgz", + "integrity": "sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz", + "integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", + "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", + "requires": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", + "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", + "requires": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.9.tgz", + "integrity": "sha512-KDlPRM6sLo4o1FkiSlXoAa8edLXFsKKIda779fbLrvmeuc3itnjCtaO6RrtoaANsIJANj+Vk1zqbZIMhkCAHVw==", + "requires": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", + "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", + "requires": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", + "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz", + "integrity": "sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-transform-numeric-separator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.4.tgz", + "integrity": "sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-transform-object-rest-spread": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz", + "integrity": "sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==", + "requires": { + "@babel/compat-data": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.23.3" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", + "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20" + } + }, + "@babel/plugin-transform-optional-catch-binding": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.4.tgz", + "integrity": "sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-transform-optional-chaining": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz", + "integrity": "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", + "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-private-methods": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz", + "integrity": "sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-private-property-in-object": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz", + "integrity": "sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", + "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-react-constant-elements": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.22.5.tgz", + "integrity": "sha512-BF5SXoO+nX3h5OhlN78XbbDrBOffv+AxPP2ENaJOVqjWCgBDeOY3WcaUcddutGSfoap+5NEQ/q/4I3WZIvgkXA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-react-display-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.22.5.tgz", + "integrity": "sha512-PVk3WPYudRF5z4GKMEYUrLjPl38fJSKNaEOkFuoprioowGuWN6w2RKznuFNSlJx7pzzXXStPUnNSOEO0jL5EVw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-react-jsx": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.5.tgz", + "integrity": "sha512-rog5gZaVbUip5iWDMTYbVM15XQq+RkUKhET/IHR6oizR+JEoN6CAfTTuHcK4vwUyzca30qqHqEpzBOnaRMWYMA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "@babel/plugin-transform-react-jsx-development": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz", + "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==", + "requires": { + "@babel/plugin-transform-react-jsx": "^7.22.5" + } + }, + "@babel/plugin-transform-react-pure-annotations": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.22.5.tgz", + "integrity": "sha512-gP4k85wx09q+brArVinTXhWiyzLl9UpmGva0+mWyKxk6JZequ05x3eUcIUE+FyttPKJFRRVtAvQaJ6YF9h1ZpA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", + "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", + "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.9.tgz", + "integrity": "sha512-9KjBH61AGJetCPYp/IEyLEp47SyybZb0nDRpBvmtEkm+rUIwxdlKpyNHI1TmsGkeuLclJdleQHRZ8XLBnnh8CQ==", + "requires": { + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "babel-plugin-polyfill-corejs2": "^0.4.4", + "babel-plugin-polyfill-corejs3": "^0.8.2", + "babel-plugin-polyfill-regenerator": "^0.5.1", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", + "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", + "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", + "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", + "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", + "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.23.6.tgz", + "integrity": "sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.23.6", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-typescript": "^7.23.3" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", + "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-unicode-property-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz", + "integrity": "sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", + "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-unicode-sets-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz", + "integrity": "sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/preset-env": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.9.tgz", + "integrity": "sha512-3kBGTNBBk9DQiPoXYS0g0BYlwTQYUTifqgKTjxUwEUkduRT2QOa0FPGBJ+NROQhGyYO5BuTJwGvBnqKDykac6A==", + "requires": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.23.3", + "@babel/plugin-syntax-import-attributes": "^7.23.3", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.23.3", + "@babel/plugin-transform-async-generator-functions": "^7.23.9", + "@babel/plugin-transform-async-to-generator": "^7.23.3", + "@babel/plugin-transform-block-scoped-functions": "^7.23.3", + "@babel/plugin-transform-block-scoping": "^7.23.4", + "@babel/plugin-transform-class-properties": "^7.23.3", + "@babel/plugin-transform-class-static-block": "^7.23.4", + "@babel/plugin-transform-classes": "^7.23.8", + "@babel/plugin-transform-computed-properties": "^7.23.3", + "@babel/plugin-transform-destructuring": "^7.23.3", + "@babel/plugin-transform-dotall-regex": "^7.23.3", + "@babel/plugin-transform-duplicate-keys": "^7.23.3", + "@babel/plugin-transform-dynamic-import": "^7.23.4", + "@babel/plugin-transform-exponentiation-operator": "^7.23.3", + "@babel/plugin-transform-export-namespace-from": "^7.23.4", + "@babel/plugin-transform-for-of": "^7.23.6", + "@babel/plugin-transform-function-name": "^7.23.3", + "@babel/plugin-transform-json-strings": "^7.23.4", + "@babel/plugin-transform-literals": "^7.23.3", + "@babel/plugin-transform-logical-assignment-operators": "^7.23.4", + "@babel/plugin-transform-member-expression-literals": "^7.23.3", + "@babel/plugin-transform-modules-amd": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.9", + "@babel/plugin-transform-modules-umd": "^7.23.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.23.3", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", + "@babel/plugin-transform-numeric-separator": "^7.23.4", + "@babel/plugin-transform-object-rest-spread": "^7.23.4", + "@babel/plugin-transform-object-super": "^7.23.3", + "@babel/plugin-transform-optional-catch-binding": "^7.23.4", + "@babel/plugin-transform-optional-chaining": "^7.23.4", + "@babel/plugin-transform-parameters": "^7.23.3", + "@babel/plugin-transform-private-methods": "^7.23.3", + "@babel/plugin-transform-private-property-in-object": "^7.23.4", + "@babel/plugin-transform-property-literals": "^7.23.3", + "@babel/plugin-transform-regenerator": "^7.23.3", + "@babel/plugin-transform-reserved-words": "^7.23.3", + "@babel/plugin-transform-shorthand-properties": "^7.23.3", + "@babel/plugin-transform-spread": "^7.23.3", + "@babel/plugin-transform-sticky-regex": "^7.23.3", + "@babel/plugin-transform-template-literals": "^7.23.3", + "@babel/plugin-transform-typeof-symbol": "^7.23.3", + "@babel/plugin-transform-unicode-escapes": "^7.23.3", + "@babel/plugin-transform-unicode-property-regex": "^7.23.3", + "@babel/plugin-transform-unicode-regex": "^7.23.3", + "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.8", + "babel-plugin-polyfill-corejs3": "^0.9.0", + "babel-plugin-polyfill-regenerator": "^0.5.5", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "dependencies": { + "@babel/helper-define-polyfill-provider": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", + "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "requires": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "requires": {} + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.9.0.tgz", + "integrity": "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==", + "requires": { + "@babel/helper-define-polyfill-provider": "^0.5.0", + "core-js-compat": "^3.34.0" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/preset-react": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.22.5.tgz", + "integrity": "sha512-M+Is3WikOpEJHgR385HbuCITPTaPRaNkibTEa9oiofmJvIsrceb4yp9RL9Kb+TE8LznmeyZqpP+Lopwcx59xPQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "@babel/plugin-transform-react-display-name": "^7.22.5", + "@babel/plugin-transform-react-jsx": "^7.22.5", + "@babel/plugin-transform-react-jsx-development": "^7.22.5", + "@babel/plugin-transform-react-pure-annotations": "^7.22.5" + } + }, + "@babel/preset-typescript": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.23.3.tgz", + "integrity": "sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", + "@babel/plugin-syntax-jsx": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-typescript": "^7.23.3" + } + }, + "@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" + }, + "@babel/runtime": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", + "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", + "requires": { + "regenerator-runtime": "^0.14.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" + } + } + }, + "@babel/runtime-corejs3": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.22.6.tgz", + "integrity": "sha512-M+37LLIRBTEVjktoJjbw4KVhupF0U/3PYUCbBwgAd9k17hoKhRu1n935QiG7Tuxv0LJOMrb2vuKEeYUlv0iyiw==", + "dev": true, + "requires": { + "core-js-pure": "^3.30.2", + "regenerator-runtime": "^0.13.11" + } + }, + "@babel/template": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "requires": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" + } + }, + "@babel/traverse": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.2.tgz", + "integrity": "sha512-s4/r+a7xTnny2O6FcZzqgT6nE4/GHEdcqj4qAeglbUOh0TeglEfmNJFAd/OLoVtGd6ZhAO8GCVvCNUO5t/VJVQ==", + "requires": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.2", + "debug": "^4.3.1", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", + "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", + "requires": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" + }, + "@csstools/normalize.css": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-12.0.0.tgz", + "integrity": "sha512-M0qqxAcwCsIVfpFQSlGN5XjXWu8l5JDZN+fPt1LeW5SZexQTgnaEvgXAY+CeygRw0EeppWHi12JxESWiWrB0Sg==" + }, + "@csstools/postcss-cascade-layers": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", + "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", + "requires": { + "@csstools/selector-specificity": "^2.0.2", + "postcss-selector-parser": "^6.0.10" + } + }, + "@csstools/postcss-color-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz", + "integrity": "sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==", + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-font-format-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz", + "integrity": "sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-hwb-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz", + "integrity": "sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-ic-unit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz", + "integrity": "sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==", + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-is-pseudo-class": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz", + "integrity": "sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==", + "requires": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + } + }, + "@csstools/postcss-nested-calc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-1.0.0.tgz", + "integrity": "sha512-JCsQsw1wjYwv1bJmgjKSoZNvf7R6+wuHDAbi5f/7MbFhl2d/+v+TvBTU4BJH3G1X1H87dHl0mh6TfYogbT/dJQ==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-normalize-display-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz", + "integrity": "sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-oklab-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz", + "integrity": "sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==", + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-progressive-custom-properties": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", + "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-stepped-value-functions": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz", + "integrity": "sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-text-decoration-shorthand": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-1.0.0.tgz", + "integrity": "sha512-c1XwKJ2eMIWrzQenN0XbcfzckOLLJiczqy+YvfGmzoVXd7pT9FfObiSEfzs84bpE/VqfpEuAZ9tCRbZkZxxbdw==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-trigonometric-functions": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz", + "integrity": "sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-unset-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz", + "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==", + "requires": {} + }, + "@csstools/selector-specificity": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz", + "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==", + "requires": {} + }, + "@dicebear/adventurer": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/adventurer/-/adventurer-8.0.1.tgz", + "integrity": "sha512-dlEycOH+yETbNo3EtswFJCnG02OEgpyPpOFmSgUuRhcRKsqbMlcsiYV4wKeRvq6VvudJXp8UiHwWszLjCHTvKA==", + "requires": {} + }, + "@dicebear/adventurer-neutral": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/adventurer-neutral/-/adventurer-neutral-8.0.1.tgz", + "integrity": "sha512-NgSz01T/K6MJn93Lk8rKPGKTx6cJe4/lNKMKjRM+4mez8S56WNdGDGUn/QY5GL3P1p01QAOMFF3hygJk3WAr3g==", + "requires": {} + }, + "@dicebear/avataaars": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/avataaars/-/avataaars-8.0.1.tgz", + "integrity": "sha512-TYXqP9mq3yHOdLlJr8saXnvxj14eY2YAmoVVbT15Rp5+kPzGDyfblNsM838sP5K6JyCNeojZsGE/sPJKk/G+mA==", + "requires": {} + }, + "@dicebear/avataaars-neutral": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/avataaars-neutral/-/avataaars-neutral-8.0.1.tgz", + "integrity": "sha512-vMV1Htaqpnz+qAVyn2tJWbRQIa6mpO/bu7dD0dumuIb45+LIpNwdUuCvkIQw2qf5ODhn1WAfYX3HEJaxRZc4lA==", + "requires": {} + }, + "@dicebear/big-ears": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/big-ears/-/big-ears-8.0.1.tgz", + "integrity": "sha512-lnPRFbXsHv2EXJR2OLqJdoUIrSVUpf1z4GkCOfAi01sYNYVpfnzg3kNF77QUhkXUhaONF7d4Wz8rUduBHRtjaA==", + "requires": {} + }, + "@dicebear/big-ears-neutral": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/big-ears-neutral/-/big-ears-neutral-8.0.1.tgz", + "integrity": "sha512-2FPvNpLI/ald3P8iWhX7SR986B8/DQlvrTNK/v+V0HRJvG1t6/7f9qfUL7OLf6plL7EgSUmKfMKacdiR5skZkA==", + "requires": {} + }, + "@dicebear/big-smile": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/big-smile/-/big-smile-8.0.1.tgz", + "integrity": "sha512-uh7FP0RgX8Qtr5zpeKUSNq028IQ3srF5LHJfQGjf4wA8R+ln/Sq0gPRJk6qMCCvPFV42b7A6f7rO7mHGnQ+qDA==", + "requires": {} + }, + "@dicebear/bottts": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/bottts/-/bottts-8.0.1.tgz", + "integrity": "sha512-WmaGZnKAT90EP/pzfUox22RshCk3GLB/p+6SsjD0ZIBNjcMXhaJroSoGVcHmPgQVzZBDIdW9C0qDKhkCNVVizg==", + "requires": {} + }, + "@dicebear/bottts-neutral": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/bottts-neutral/-/bottts-neutral-8.0.1.tgz", + "integrity": "sha512-krbD3U+UvzlY+kfQDpg9Hql1xJmmu3y9ensiU+XZXiuNw/ZavgGqpJtzpbYeF3J5GsggQlbBh/ZAK9AIKz7S3Q==", + "requires": {} + }, + "@dicebear/collection": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/collection/-/collection-8.0.1.tgz", + "integrity": "sha512-RlWvOOXTxqP1llNzWhrnm6wCMKFAku/Ty0YJNv+4LYA1YIDpyLNN2PwxxCuj7hU244qUwQcVPQPPPr0XQ+rA/g==", + "requires": { + "@dicebear/adventurer": "8.0.1", + "@dicebear/adventurer-neutral": "8.0.1", + "@dicebear/avataaars": "8.0.1", + "@dicebear/avataaars-neutral": "8.0.1", + "@dicebear/big-ears": "8.0.1", + "@dicebear/big-ears-neutral": "8.0.1", + "@dicebear/big-smile": "8.0.1", + "@dicebear/bottts": "8.0.1", + "@dicebear/bottts-neutral": "8.0.1", + "@dicebear/croodles": "8.0.1", + "@dicebear/croodles-neutral": "8.0.1", + "@dicebear/fun-emoji": "8.0.1", + "@dicebear/icons": "8.0.1", + "@dicebear/identicon": "8.0.1", + "@dicebear/initials": "8.0.1", + "@dicebear/lorelei": "8.0.1", + "@dicebear/lorelei-neutral": "8.0.1", + "@dicebear/micah": "8.0.1", + "@dicebear/miniavs": "8.0.1", + "@dicebear/notionists": "8.0.1", + "@dicebear/notionists-neutral": "8.0.1", + "@dicebear/open-peeps": "8.0.1", + "@dicebear/personas": "8.0.1", + "@dicebear/pixel-art": "8.0.1", + "@dicebear/pixel-art-neutral": "8.0.1", + "@dicebear/rings": "8.0.1", + "@dicebear/shapes": "8.0.1", + "@dicebear/thumbs": "8.0.1" + } + }, + "@dicebear/converter": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/converter/-/converter-8.0.1.tgz", + "integrity": "sha512-65L04fN4V07WcUnwQuDYDH+zrP8WA6/UeIuqqH/Pv7VWoJtIk9qHlaA+XGpPr4qgRtkmY7uXVkrED/RMlqvUDA==", + "requires": { + "@types/json-schema": "^7.0.11", + "tmp-promise": "^3.0.3" + } + }, + "@dicebear/core": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/core/-/core-8.0.1.tgz", + "integrity": "sha512-HWqvQRpVjkboQXinCOjU3poZIMd5p+32wPvc9N5fYiXe3KQLhJNw5T5XiRttDUm3XpoTvhQ4DVTPDsXT8CqrTg==", + "requires": { + "@dicebear/converter": "8.0.1", + "@types/json-schema": "^7.0.11" + } + }, + "@dicebear/croodles": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/croodles/-/croodles-8.0.1.tgz", + "integrity": "sha512-4si6gm61hEI8uDk+7OhSX+0qSPfotYx1dbdBphgGgiP9KTOgipnXzNtz8YnGzNf+V89nV4twHa6Bl6Wna4kFYA==", + "requires": {} + }, + "@dicebear/croodles-neutral": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/croodles-neutral/-/croodles-neutral-8.0.1.tgz", + "integrity": "sha512-DlR1wxzacRc3GhkMRg4MJ4CBfci/Z96SUl3YpvhHQ4ZtPldaQmdxs3jzOlnG1cuNRkqmiB1D66EXj5146V5WMA==", + "requires": {} + }, + "@dicebear/fun-emoji": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/fun-emoji/-/fun-emoji-8.0.1.tgz", + "integrity": "sha512-s2zXyZ7Rp3E2OHxAghhKIYmTtQ64D1VU+/p0VNaIQTPnyfxgpdrKlBMAlp4fXHyirhtAWCHSWgXcU9UFvlmr+w==", + "requires": {} + }, + "@dicebear/icons": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/icons/-/icons-8.0.1.tgz", + "integrity": "sha512-uInO34VW1etgMsbarXIeYULTk+dlj0L9vW7nUinWqwwEbimgXT4iqzNSjQyogmQ3wmaahI1zNwrGUkfkQojouw==", + "requires": {} + }, + "@dicebear/identicon": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/identicon/-/identicon-8.0.1.tgz", + "integrity": "sha512-mIHBuUlTs1RNZg+9k4NIjYXYjZBh08ksK/7Pmb+5twsoIPuAPjZ+FbQsfc27Wga/IuJfgf9mYBq6Sxc8/LQxjg==", + "requires": {} + }, + "@dicebear/initials": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/initials/-/initials-8.0.1.tgz", + "integrity": "sha512-ctO1f92XAms72qkhiKI/vvS/E6mco1RiTEACPJGv6hDPfdjR1vxpkzFpo3jm3RohfwOPCN5fH2l3BSinnlbzzw==", + "requires": {} + }, + "@dicebear/lorelei": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/lorelei/-/lorelei-8.0.1.tgz", + "integrity": "sha512-AY9XDeV7pIojDziiT/9flPWvH/5dswlVvezHQljmLa1H6EIQAIRWj9INeDaS2u2hRTFQKVeYQ1kuP3Omb+t26A==", + "requires": {} + }, + "@dicebear/lorelei-neutral": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/lorelei-neutral/-/lorelei-neutral-8.0.1.tgz", + "integrity": "sha512-vC5M7jg6UByJyFjBitLB3xKr435FdH8BHD8oVzf9A2MXi/ovQ0bEak9MnxVcrxUufJx7bsgS/XCRYNLUwaQKyw==", + "requires": {} + }, + "@dicebear/micah": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/micah/-/micah-8.0.1.tgz", + "integrity": "sha512-B7+YCX62CqnjLlJNY6+NXy+HJlyGMzCbrnE38bGdmnH7PZ1IrEnmJny41AcopKziE02h65kdwCZFXy/v7piT4g==", + "requires": {} + }, + "@dicebear/miniavs": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/miniavs/-/miniavs-8.0.1.tgz", + "integrity": "sha512-mzNAa2cIvsyeRuSnWoQ6l23yiw4BhmzrwdmfJZuDLloh/UNJjyiiCItYSTBmhtxcJrWX8YQTd/2hPdXjsdceTA==", + "requires": {} + }, + "@dicebear/notionists": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/notionists/-/notionists-8.0.1.tgz", + "integrity": "sha512-wOZPSj7lKIJkxiJHysGUVehPmaisWV9dUNhs4jDApiit3u6cbspDEOXvlAn/68cpGP8LfjsdyCp8yhZ9Wvk15Q==", + "requires": {} + }, + "@dicebear/notionists-neutral": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/notionists-neutral/-/notionists-neutral-8.0.1.tgz", + "integrity": "sha512-j70iiLZPpLw9JfyziRC8jUaVnbz2NPTZFMd+O08ba3FcTsG0H5+bYimTWL+6fxZ/psN1S3NS/onVvgPkvBWTjg==", + "requires": {} + }, + "@dicebear/open-peeps": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/open-peeps/-/open-peeps-8.0.1.tgz", + "integrity": "sha512-NQbXmnPjyz3YZOAIEzQY6OFXg3sCIIDZgQZjl3qzTqsmUtZVMRnX8Sk53ig1SIM1kxIAyJ908wplwIYV16zxsw==", + "requires": {} + }, + "@dicebear/personas": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/personas/-/personas-8.0.1.tgz", + "integrity": "sha512-qxivUbnx4xvE1PvqCg6pBQadVDJVjXaXnxtIUxIRJyDeYIJUxkeBr2A5JOIiNLdypqXoYwhURy5r3NCmesaAWg==", + "requires": {} + }, + "@dicebear/pixel-art": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/pixel-art/-/pixel-art-8.0.1.tgz", + "integrity": "sha512-WMRKdxP8/PL2UGiLAP7CdgTNaIRpFyLdr+u6RyXAUmWiI25ltnZQjctzCfUrO/Nxywc6L6lBkApZtTaP+X+UHg==", + "requires": {} + }, + "@dicebear/pixel-art-neutral": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/pixel-art-neutral/-/pixel-art-neutral-8.0.1.tgz", + "integrity": "sha512-jrbwMNjLk8hlOm+hMTT43z2DqXEFtv6/8hhms7VZE9FjcB1GrQy8j6tSClTq/ktkZlWofEGfvD8BrG5HsbKvaw==", + "requires": {} + }, + "@dicebear/rings": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/rings/-/rings-8.0.1.tgz", + "integrity": "sha512-RcSXPJDdDiyAscUhJMI6pgOgk4or0nzjKndur44U6I+6s0qS3c74zfT//whLUnDnSO2ZTaUGAjQ5gGJtzp5fqQ==", + "requires": {} + }, + "@dicebear/shapes": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/shapes/-/shapes-8.0.1.tgz", + "integrity": "sha512-Duhe3bcKmcYt7GcUsNP4/OIbcHzgb4L7rfuMpUgqjXKATLYq1Wizsw9/y9wrwII8h7wIMxG6RDSndNbd7ISTtA==", + "requires": {} + }, + "@dicebear/thumbs": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@dicebear/thumbs/-/thumbs-8.0.1.tgz", + "integrity": "sha512-cK3UeVVWtiGbStpYeKJrCw3Wy+LGNS5sFja2O3ogc/qpjiL7WFX7kYJXOE2neqOUxVItDxg7dfGatxFrsgUTYA==", + "requires": {} + }, + "@emotion/babel-plugin": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", + "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "requires": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/serialize": "^1.1.2", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "requires": { + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + } + }, + "@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + }, + "@emotion/is-prop-valid": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", + "integrity": "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==", + "requires": { + "@emotion/memoize": "^0.8.1" + } + }, + "@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "@emotion/react": { + "version": "11.11.4", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.4.tgz", + "integrity": "sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==", + "requires": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/cache": "^11.11.0", + "@emotion/serialize": "^1.1.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "hoist-non-react-statics": "^3.3.1" + } + }, + "@emotion/serialize": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.4.tgz", + "integrity": "sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ==", + "requires": { + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/unitless": "^0.8.1", + "@emotion/utils": "^1.2.1", + "csstype": "^3.0.2" + } + }, + "@emotion/sheet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + }, + "@emotion/styled": { + "version": "11.11.5", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.5.tgz", + "integrity": "sha512-/ZjjnaNKvuMPxcIiUkf/9SHoG4Q196DRl1w82hQ3WCsjo1IUR8uaGWrC6a87CrYAW0Kb/pK7hk8BnLgLRi9KoQ==", + "requires": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/is-prop-valid": "^1.2.2", + "@emotion/serialize": "^1.1.4", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1" + } + }, + "@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + }, + "@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", + "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "requires": {} + }, + "@emotion/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + }, + "@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + }, + "@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "dev": true, + "optional": true + }, + "@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==", + "dev": true, + "optional": true + }, + "@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==", + "dev": true, + "optional": true + }, + "@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==", + "dev": true, + "optional": true + }, + "@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==", + "dev": true, + "optional": true + }, + "@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==", + "dev": true, + "optional": true + }, + "@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==", + "dev": true, + "optional": true + }, + "@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==", + "dev": true, + "optional": true + }, + "@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==", + "dev": true, + "optional": true + }, + "@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==", + "dev": true, + "optional": true + }, + "@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==", + "dev": true, + "optional": true + }, + "@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==", + "dev": true, + "optional": true + }, + "@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==", + "dev": true, + "optional": true + }, + "@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==", + "dev": true, + "optional": true + }, + "@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==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "dev": true, + "optional": true + }, + "@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==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "dev": true, + "optional": true + }, + "@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==", + "dev": true, + "optional": true + }, + "@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==", + "dev": true, + "optional": true + }, + "@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==", + "dev": true, + "optional": true + }, + "@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==", + "dev": true, + "optional": true + }, + "@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==", + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", + "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==" + }, + "@eslint/eslintrc": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", + "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", + "requires": { + "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" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "requires": { + "type-fest": "^0.20.2" + } + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + }, + "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==" + }, + "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==" + } + } + }, + "@eslint/js": { + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", + "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==" + }, + "@floating-ui/core": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.1.tgz", + "integrity": "sha512-42UH54oPZHPdRHdw6BgoBD6cg/eVTmVrFcgeRDM3jbO7uxSoipVcmcIGFcA5jmOHO5apcyvBhkSKES3fQJnu7A==", + "requires": { + "@floating-ui/utils": "^0.2.0" + } + }, + "@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==", + "requires": { + "@floating-ui/core": "^1.0.0", + "@floating-ui/utils": "^0.2.0" + } + }, + "@floating-ui/react": { + "version": "0.26.19", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.19.tgz", + "integrity": "sha512-Jk6zITdjjIvjO/VdQFvpRaD3qPwOHH6AoDHxjhpy+oK4KFgaSP871HYWUAPdnLmx1gQ+w/pB312co3tVml+BXA==", + "requires": { + "@floating-ui/react-dom": "^2.1.1", + "@floating-ui/utils": "^0.2.4", + "tabbable": "^6.0.0" + } + }, + "@floating-ui/react-dom": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz", + "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==", + "requires": { + "@floating-ui/dom": "^1.0.0" + } + }, + "@floating-ui/utils": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.4.tgz", + "integrity": "sha512-dWO2pw8hhi+WrXq1YJy2yCuWoL20PddgGaqTgVe4cOS9Q6qklXCiA1tJEqX6BEwRNSCP84/afac9hd4MS+zEUA==" + }, + "@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "optional": true, + "peer": true + }, + "@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==", + "requires": {} + }, + "@humanwhocodes/config-array": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==" + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + }, + "@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==", + "requires": { + "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" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + } + } + }, + "@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==" + }, + "@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 + }, + "@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "requires": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==", + "requires": { + "@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" + } + } + } + }, + "@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "requires": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "requires": { + "@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" + } + }, + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==" + }, + "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==" + }, + "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==", + "requires": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "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" + } + }, + "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==" + }, + "jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "requires": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + } + }, + "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==", + "requires": { + "@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" + } + }, + "jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "requires": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + } + }, + "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==", + "requires": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "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==", + "requires": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "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==" + } + } + }, + "resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==" + }, + "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==", + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + } + } + }, + "@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "requires": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "dependencies": { + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "requires": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + } + }, + "@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "requires": { + "jest-get-type": "^29.6.3" + }, + "dependencies": { + "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==" + } + } + }, + "@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "requires": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "dependencies": { + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==", + "requires": { + "@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" + } + } + } + }, + "@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "requires": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "dependencies": { + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "dependencies": { + "@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "requires": { + "@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" + } + }, + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==" + }, + "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==", + "requires": { + "@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" + } + }, + "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==", + "requires": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "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" + } + }, + "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==" + }, + "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==", + "requires": { + "@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" + } + }, + "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==", + "requires": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "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==", + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + } + } + }, + "@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==", + "requires": { + "@sinclair/typebox": "^0.27.8" + } + }, + "@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "requires": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + } + }, + "@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "requires": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "requires": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==", + "requires": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "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" + } + }, + "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==" + }, + "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==", + "requires": { + "@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" + } + }, + "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==", + "requires": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + } + } + }, + "@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "requires": { + "@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" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "@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==", + "requires": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@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==" + }, + "@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==" + }, + "@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==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@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==" + }, + "@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==", + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" + }, + "@microsoft/tsdoc": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz", + "integrity": "sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==", + "dev": true + }, + "@microsoft/tsdoc-config": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz", + "integrity": "sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==", + "dev": true, + "requires": { + "@microsoft/tsdoc": "0.14.2", + "ajv": "~6.12.6", + "jju": "~1.4.0", + "resolve": "~1.19.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "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 + }, + "resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "requires": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + } + } + } + }, + "@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==", + "requires": { + "@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" + }, + "dependencies": { + "clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==" + } + } + }, + "@mui/core-downloads-tracker": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.4.tgz", + "integrity": "sha512-rNdHXhclwjEZnK+//3SR43YRx0VtjdHnUFhMSGYmAMJve+KiwEja/41EYh8V3pZKqF2geKyfcFUenTfDTYUR4w==" + }, + "@mui/icons-material": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.16.1.tgz", + "integrity": "sha512-ogQPweYba4+5XZykilwxn2/oS78uwoQ0BVBpOhhCJo0ooZsqTTsalhzP2qD/RdGqMQ8xyXPz1sYM2djTruVVVA==", + "requires": { + "@babel/runtime": "^7.23.9" + } + }, + "@mui/material": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.4.tgz", + "integrity": "sha512-dBnh3/zRYgEVIS3OE4oTbujse3gifA0qLMmuUk13ywsDCbngJsdgwW5LuYeiT5pfA8PGPGSqM7mxNytYXgiMCw==", + "requires": { + "@babel/runtime": "^7.23.9", + "@mui/core-downloads-tracker": "^5.16.4", + "@mui/system": "^5.16.4", + "@mui/types": "^7.2.15", + "@mui/utils": "^5.16.4", + "@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" + }, + "dependencies": { + "clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==" + } + } + }, + "@mui/private-theming": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.4.tgz", + "integrity": "sha512-ZsAm8cq31SJ37SVWLRlu02v9SRthxnfQofaiv14L5Bht51B0dz6yQEoVU/V8UduZDCCIrWkBHuReVfKhE/UuXA==", + "requires": { + "@babel/runtime": "^7.23.9", + "@mui/utils": "^5.16.4", + "prop-types": "^15.8.1" + } + }, + "@mui/styled-engine": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.4.tgz", + "integrity": "sha512-0+mnkf+UiAmTVB8PZFqOhqf729Yh0Cxq29/5cA3VAyDVTRIUUQ8FXQhiAhUIbijFmM72rY80ahFPXIm4WDbzcA==", + "requires": { + "@babel/runtime": "^7.23.9", + "@emotion/cache": "^11.11.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + } + }, + "@mui/system": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.4.tgz", + "integrity": "sha512-ET1Ujl2/8hbsD611/mqUuNArMCGv/fIWO/f8B3ZqF5iyPHM2aS74vhTNyjytncc4i6dYwGxNk+tLa7GwjNS0/w==", + "requires": { + "@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" + }, + "dependencies": { + "clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==" + } + } + }, + "@mui/types": { + "version": "7.2.15", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.15.tgz", + "integrity": "sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q==", + "requires": {} + }, + "@mui/utils": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.4.tgz", + "integrity": "sha512-nlppYwq10TBIFqp7qxY0SvbACOXeOjeVL3pOcDsK0FT8XjrEXh9/+lkg8AEIzD16z7YfiJDQjaJG2OLkE7BxNg==", + "requires": { + "@babel/runtime": "^7.23.9", + "@types/prop-types": "^15.7.12", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^18.3.1" + }, + "dependencies": { + "clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==" + } + } + }, + "@mui/x-charts": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@mui/x-charts/-/x-charts-7.8.0.tgz", + "integrity": "sha512-SosaVtx4Ig1nu/loH6Mq4peH5Pq5UvVEnsMfe4G2IEVrMxfwrktWJo+86t9LxiHTERt4wxPKnsqlhkgBIf9ePQ==", + "requires": { + "@babel/runtime": "^7.24.7", + "@mui/base": "^5.0.0-beta.40", + "@mui/system": "^5.15.20", + "@mui/utils": "^5.15.20", + "@react-spring/rafz": "^9.7.3", + "@react-spring/web": "^9.7.3", + "clsx": "^2.1.1", + "d3-color": "^3.1.0", + "d3-delaunay": "^6.0.4", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.2.0", + "prop-types": "^15.8.1" + }, + "dependencies": { + "clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==" + } + } + }, + "@mui/x-data-grid": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-7.11.0.tgz", + "integrity": "sha512-dXaIw3Noxc4d6xenS7J+zMPORG9ptkTW7B81P6QFovILSEuI/qebQhijy/IkqRvcCsuZYLL3nA89bp+EDI503Q==", + "requires": { + "@babel/runtime": "^7.24.8", + "@mui/system": "^5.16.2", + "@mui/utils": "^5.16.2", + "@mui/x-internals": "7.11.0", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "reselect": "^4.1.8" + }, + "dependencies": { + "clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==" + } + } + }, + "@mui/x-date-pickers": { + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.6.1.tgz", + "integrity": "sha512-erSq5cnOUyBgBmpHnMxIit5yhT3bl/lOaNZKpObvJtvEJetvNA9xWQ7dz/J/AufLzDuvThjusuRD0y+GmeXtiw==", + "requires": { + "@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" + }, + "dependencies": { + "clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==" + } + } + }, + "@mui/x-internals": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.11.0.tgz", + "integrity": "sha512-GqCYylKiB4cLH9tK4JweJlT2JvPjnpXjS3TEIqtHB4BcSsezhdRrMGzHOO5zCJqkasqTirJh2t6X16Qw1llr4Q==", + "requires": { + "@babel/runtime": "^7.24.8", + "@mui/utils": "^5.16.2" + } + }, + "@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "requires": { + "eslint-scope": "5.1.1" + } + }, + "@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==", + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@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==" + }, + "@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==", + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@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==", + "requires": { + "pako": "^1.0.6" + } + }, + "@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==", + "requires": { + "pako": "^1.0.10" + } + }, + "@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==", + "requires": { + "buffer": "^6.0.3", + "fontkit": "^2.0.2", + "zod": "^3.20.2" + } + }, + "@pdfme/generator": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@pdfme/generator/-/generator-1.2.6.tgz", + "integrity": "sha512-rAkhr4vYa0OxVubAvLI/UIgD9+sCrcBG1SZpFCBVILgZjpqkUsscXdyukRtmHP6WaNAFGINch6PZVoshyQdGPw==", + "requires": { + "@pdfme/common": "latest", + "@pdfme/pdf-lib": "^1.17.3", + "atob": "^2.1.2", + "bwip-js": "^3.2.2", + "fontkit": "^2.0.2" + } + }, + "@pdfme/pdf-lib": { + "version": "1.17.3", + "resolved": "https://registry.npmjs.org/@pdfme/pdf-lib/-/pdf-lib-1.17.3.tgz", + "integrity": "sha512-k3cyms42I7jVycwDuzZuLD7A9J/D8Ud1iGJ7BpAfF54QYKxG0mUG6jTDJnc+tHrpNrsoJ4iFqERy5XvMQ6SUsA==", + "requires": { + "@pdf-lib/standard-fonts": "^1.0.0", + "@pdf-lib/upng": "^1.0.1", + "pako": "^1.0.11", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true + }, + "@pmmmwh/react-refresh-webpack-plugin": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.10.tgz", + "integrity": "sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA==", + "requires": { + "ansi-html-community": "^0.0.8", + "common-path-prefix": "^3.0.0", + "core-js-pure": "^3.23.3", + "error-stack-parser": "^2.0.6", + "find-up": "^5.0.0", + "html-entities": "^2.1.0", + "loader-utils": "^2.0.4", + "schema-utils": "^3.0.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "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==", + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "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==", + "requires": { + "p-locate": "^5.0.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "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==", + "requires": { + "p-limit": "^3.0.2" + } + }, + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==" + } + } + }, + "@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 + }, + "@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==" + }, + "@react-aria/ssr": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.7.0.tgz", + "integrity": "sha512-bfufjg4ESE5giN+Fxj1XIzS5f/YIhqcGc+Ve+vUUKU8xZ8t/Xtjlv8F3kjqDBQdk//n3mluFY7xG1wQVB9rMLQ==", + "requires": { + "@swc/helpers": "^0.5.0" + }, + "dependencies": { + "@swc/helpers": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", + "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", + "requires": { + "tslib": "^2.4.0" + } + } + } + }, + "@react-spring/animated": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.3.tgz", + "integrity": "sha512-5CWeNJt9pNgyvuSzQH+uy2pvTg8Y4/OisoscZIR8/ZNLIOI+CatFBhGZpDGTF/OzdNFsAoGk3wiUYTwoJ0YIvw==", + "requires": { + "@react-spring/shared": "~9.7.3", + "@react-spring/types": "~9.7.3" + } + }, + "@react-spring/core": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.3.tgz", + "integrity": "sha512-IqFdPVf3ZOC1Cx7+M0cXf4odNLxDC+n7IN3MDcVCTIOSBfqEcBebSv+vlY5AhM0zw05PDbjKrNmBpzv/AqpjnQ==", + "requires": { + "@react-spring/animated": "~9.7.3", + "@react-spring/shared": "~9.7.3", + "@react-spring/types": "~9.7.3" + } + }, + "@react-spring/rafz": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.3.tgz", + "integrity": "sha512-9vzW1zJPcC4nS3aCV+GgcsK/WLaB520Iyvm55ARHfM5AuyBqycjvh1wbmWmgCyJuX4VPoWigzemq1CaaeRSHhQ==" + }, + "@react-spring/shared": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.3.tgz", + "integrity": "sha512-NEopD+9S5xYyQ0pGtioacLhL2luflh6HACSSDUZOwLHoxA5eku1UPuqcJqjwSD6luKjjLfiLOspxo43FUHKKSA==", + "requires": { + "@react-spring/types": "~9.7.3" + } + }, + "@react-spring/types": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.3.tgz", + "integrity": "sha512-Kpx/fQ/ZFX31OtlqVEFfgaD1ACzul4NksrvIgYfIFq9JpDHFwQkMVZ10tbo0FU/grje4rcL4EIrjekl3kYwgWw==" + }, + "@react-spring/web": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.3.tgz", + "integrity": "sha512-BXt6BpS9aJL/QdVqEIX9YoUy8CE6TJrU0mNCqSoxdXlIeNcEBWOfIyE6B14ENNsyQKS3wOWkiJfco0tCr/9tUg==", + "requires": { + "@react-spring/animated": "~9.7.3", + "@react-spring/core": "~9.7.3", + "@react-spring/shared": "~9.7.3", + "@react-spring/types": "~9.7.3" + } + }, + "@remix-run/router": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.18.0.tgz", + "integrity": "sha512-L3jkqmqoSVBVKHfpGZmLrex0lxR5SucGA0sUfFzGctehw+S/ggL9L/0NnC5mw6P8HUWpFZ3nQw3cRApjjWx9Sw==" + }, + "@restart/hooks": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.10.tgz", + "integrity": "sha512-HVZhYHb+9xnN6vDPyiTmw6N4V5wD9tatL3y0zpHFeeatP1ooOD1edzd3MnJCXYlb3OeleDg+Vv16EikGrH57eA==", + "requires": { + "dequal": "^2.0.3" + } + }, + "@restart/ui": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.6.6.tgz", + "integrity": "sha512-eC3puKuWE1SRYbojWHXnvCNHGgf3uzHCb6JOhnF4OXPibOIPEkR1sqDSkL643ydigxwh+ruCa1CmYHlzk7ikKA==", + "requires": { + "@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" + }, + "dependencies": { + "uncontrollable": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.2.tgz", + "integrity": "sha512-/GDx+K1STGtpgTsj5Dj3J51YaKxZDblbCQHTH1zHLuoBEWodj6MjtRVv3TUijj1JYLRLSFsFzN8NV4M3QV4d9w==", + "requires": {} + } + } + }, + "@rollup/plugin-babel": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", + "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", + "requires": { + "@babel/helper-module-imports": "^7.10.4", + "@rollup/pluginutils": "^3.1.0" + } + }, + "@rollup/plugin-node-resolve": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", + "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", + "requires": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + } + }, + "@rollup/plugin-replace": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", + "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", + "requires": { + "@rollup/pluginutils": "^3.1.0", + "magic-string": "^0.25.7" + } + }, + "@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "dependencies": { + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" + } + } + }, + "@rushstack/eslint-patch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.2.tgz", + "integrity": "sha512-V+MvGwaHH03hYhY+k6Ef/xKd6RYlc4q8WBx+2ANmipHJcKuktNcI/NgEsJgdSUF6Lw32njT6OnrRsKYCdgHjYw==" + }, + "@shikijs/core": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.10.3.tgz", + "integrity": "sha512-D45PMaBaeDHxww+EkcDQtDAtzv00Gcsp72ukBtaLSmqRvh0WgGMq3Al0rl1QQBZfuneO75NXMIzEZGFitThWbg==", + "peer": true, + "requires": { + "@types/hast": "^3.0.4" + } + }, + "@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==" + }, + "@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 + }, + "@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "requires": { + "@sinonjs/commons": "^3.0.0" + } + }, + "@surma/rollup-plugin-off-main-thread": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", + "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", + "requires": { + "ejs": "^3.1.6", + "json5": "^2.2.0", + "magic-string": "^0.25.0", + "string.prototype.matchall": "^4.0.6" + } + }, + "@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, + "requires": {} + }, + "@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, + "requires": {} + }, + "@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, + "requires": {} + }, + "@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, + "requires": {} + }, + "@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, + "requires": {} + }, + "@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, + "requires": {} + }, + "@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, + "requires": {} + }, + "@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, + "requires": {} + }, + "@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, + "requires": { + "@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" + } + }, + "@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, + "requires": { + "@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" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + } + } + }, + "@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, + "requires": { + "@babel/types": "^7.20.0", + "entities": "^4.4.0" + } + }, + "@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, + "requires": { + "@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" + } + }, + "@svgr/plugin-svgo": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz", + "integrity": "sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ==", + "requires": { + "cosmiconfig": "^7.0.0", + "deepmerge": "^4.2.2", + "svgo": "^1.2.2" + } + }, + "@svgr/webpack": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.5.0.tgz", + "integrity": "sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g==", + "requires": { + "@babel/core": "^7.12.3", + "@babel/plugin-transform-react-constant-elements": "^7.12.1", + "@babel/preset-env": "^7.12.1", + "@babel/preset-react": "^7.12.5", + "@svgr/core": "^5.5.0", + "@svgr/plugin-jsx": "^5.5.0", + "@svgr/plugin-svgo": "^5.5.0", + "loader-utils": "^2.0.0" + }, + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg==" + }, + "@svgr/babel-plugin-remove-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg==" + }, + "@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz", + "integrity": "sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA==" + }, + "@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz", + "integrity": "sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ==" + }, + "@svgr/babel-plugin-svg-dynamic-title": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz", + "integrity": "sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg==" + }, + "@svgr/babel-plugin-svg-em-dimensions": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz", + "integrity": "sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw==" + }, + "@svgr/babel-plugin-transform-react-native-svg": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz", + "integrity": "sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q==" + }, + "@svgr/babel-plugin-transform-svg-component": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz", + "integrity": "sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ==" + }, + "@svgr/babel-preset": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-5.5.0.tgz", + "integrity": "sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==", + "requires": { + "@svgr/babel-plugin-add-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "^5.0.1", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^5.0.1", + "@svgr/babel-plugin-svg-dynamic-title": "^5.4.0", + "@svgr/babel-plugin-svg-em-dimensions": "^5.4.0", + "@svgr/babel-plugin-transform-react-native-svg": "^5.4.0", + "@svgr/babel-plugin-transform-svg-component": "^5.5.0" + } + }, + "@svgr/core": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz", + "integrity": "sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==", + "requires": { + "@svgr/plugin-jsx": "^5.5.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^7.0.0" + } + }, + "@svgr/hast-util-to-babel-ast": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz", + "integrity": "sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==", + "requires": { + "@babel/types": "^7.12.6" + } + }, + "@svgr/plugin-jsx": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz", + "integrity": "sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==", + "requires": { + "@babel/core": "^7.12.3", + "@svgr/babel-preset": "^5.5.0", + "@svgr/hast-util-to-babel-ast": "^5.5.0", + "svg-parser": "^2.0.2" + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" + }, + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "@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==", + "requires": { + "tslib": "^2.4.0" + } + }, + "@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, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@testing-library/dom": { + "version": "7.31.2", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", + "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^4.2.0", + "aria-query": "^4.2.2", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.6", + "lz-string": "^1.4.4", + "pretty-format": "^26.6.2" + }, + "dependencies": { + "aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "@testing-library/jest-dom": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.5.tgz", + "integrity": "sha512-AguB9yvTXmCnySBP1lWjfNNUwpbElsaQ567lt2VdGqAdHtpieLgjmcVyv1q7PMIvLbgpDdkWV5Ydv3FEejyp2A==", + "dev": true, + "requires": { + "@adobe/css-tools": "^4.3.2", + "@babel/runtime": "^7.9.2", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.21", + "redent": "^3.0.0" + }, + "dependencies": { + "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 + } + } + }, + "@testing-library/react": { + "version": "11.2.7", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-11.2.7.tgz", + "integrity": "sha512-tzRNp7pzd5QmbtXNG/mhdcl7Awfu/Iz1RaVHY75zTdOkmHCuzMhRL83gWHSgOAcjS3CCbyfwUHMZgRJb4kAfpA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.12.5", + "@testing-library/dom": "^7.28.1" + } + }, + "@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, + "requires": { + "@babel/runtime": "^7.12.5" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" + }, + "@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==" + }, + "@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, + "@types/babel__core": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", + "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==", + "requires": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@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==", + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@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==", + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@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==", + "requires": { + "@babel/types": "^7.20.7" + } + }, + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "requires": { + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "requires": { + "@types/node": "*" + } + }, + "@types/connect-history-api-fallback": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz", + "integrity": "sha512-4x5FkPpLipqwthjPsF7ZRbOv3uoLUFkTA9G9v583qi4pACvq0uTELrB8OLUzPWUI4IJIyvM85vzkV1nyiI2Lig==", + "requires": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "@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==", + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==" + }, + "@types/express": { + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.35", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz", + "integrity": "sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==", + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "@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==", + "requires": { + "@types/node": "*" + } + }, + "@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==", + "peer": true, + "requires": { + "@types/unist": "*" + } + }, + "@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 + }, + "@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "requires": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, + "@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" + }, + "@types/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==" + }, + "@types/http-proxy": { + "version": "1.17.11", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.11.tgz", + "integrity": "sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA==", + "requires": { + "@types/node": "*" + } + }, + "@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, + "requires": { + "@types/through": "*", + "rxjs": "^7.2.0" + } + }, + "@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==" + }, + "@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==", + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@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==", + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/jest": { + "version": "29.5.12", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", + "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", + "dev": true, + "requires": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + }, + "dependencies": { + "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, + "requires": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "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 + } + } + } + } + }, + "@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 + }, + "@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==" + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" + }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + }, + "@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "optional": true, + "peer": true + }, + "@types/node": { + "version": "20.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", + "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", + "requires": { + "undici-types": "~5.26.4" + } + }, + "@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, + "requires": { + "@types/node": "*", + "form-data": "^4.0.0" + }, + "dependencies": { + "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, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + } + } + }, + "@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "optional": true, + "peer": true + }, + "@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==" + }, + "@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==" + }, + "@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==" + }, + "@types/q": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", + "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==" + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" + }, + "@types/react": { + "version": "17.0.62", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.62.tgz", + "integrity": "sha512-eANCyz9DG8p/Vdhr0ZKST8JV12PhH2ACCDYlFw6DIO+D+ca+uP4jtEDEpVqXZrh/uZdXQGwk7whJa3ah5DtyLw==", + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@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, + "requires": { + "@types/react": "*" + } + }, + "@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, + "requires": { + "@types/react": "*" + } + }, + "@types/react-datepicker": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@types/react-datepicker/-/react-datepicker-4.11.2.tgz", + "integrity": "sha512-ELYyX3lb3K1WltqdlF1hbnaDGgzlF6PIR5T4W38cSEcfrQDIrPE+Ioq5pwRe/KEJ+ihHMjvTVZQkwJx0pWMNHQ==", + "dev": true, + "requires": { + "@popperjs/core": "^2.9.2", + "@types/react": "*", + "date-fns": "^2.0.1", + "react-popper": "^2.2.5" + } + }, + "@types/react-dom": { + "version": "17.0.20", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.20.tgz", + "integrity": "sha512-4pzIjSxDueZZ90F52mU3aPoogkHIoSIDG+oQ+wQK7Cy2B9S+MvOqY0uEA/qawKz381qrEDkvpwyt8Bm31I8sbA==", + "dev": true, + "requires": { + "@types/react": "^17" + } + }, + "@types/react-google-recaptcha": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/react-google-recaptcha/-/react-google-recaptcha-2.1.5.tgz", + "integrity": "sha512-iWTjmVttlNgp0teyh7eBXqNOQzVq2RWNiFROWjraOptRnb1OcHJehQnji0sjqIRAk9K0z8stjyhU+OLpPb0N6w==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, + "@types/react-redux": { + "version": "7.1.25", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.25.tgz", + "integrity": "sha512-bAGh4e+w5D8dajd6InASVIyCo4pZLJ66oLb80F9OBLO1gKESbZcRCJpTT6uLXX+HAB57zw1WTdwJdAsewuTweg==", + "requires": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, + "@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, + "requires": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "@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, + "requires": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "@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==", + "requires": { + "@types/react": "*" + } + }, + "@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "requires": { + "@types/node": "*" + } + }, + "@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + }, + "@types/sanitize-html": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.11.0.tgz", + "integrity": "sha512-7oxPGNQHXLHE48r/r/qjn7q0hlrs3kL7oZnGj0Wf/h9tj/6ibFyRkNbsDxaBBZ4XUZ0Dx5LGCyDJ04ytSofacQ==", + "dev": true, + "requires": { + "htmlparser2": "^8.0.0" + } + }, + "@types/scheduler": { + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", + "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" + }, + "@types/semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==" + }, + "@types/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", + "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "requires": { + "@types/express": "*" + } + }, + "@types/serve-static": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.2.tgz", + "integrity": "sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw==", + "requires": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, + "@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "requires": { + "@types/node": "*" + } + }, + "@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==" + }, + "@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, + "requires": { + "@types/node": "*" + } + }, + "@types/trusted-types": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz", + "integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==" + }, + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==", + "peer": true + }, + "@types/warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz", + "integrity": "sha512-t/Tvs5qR47OLOr+4E9ckN8AmP2Tf16gWq+/qA4iUGS/OOyHVO8wv2vjJuX8SNOUTJyWb+2t7wJm6cXILFnOROA==" + }, + "@types/ws": { + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", + "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", + "requires": { + "@types/node": "*" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "@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==" + }, + "@typescript-eslint/eslint-plugin": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "requires": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/experimental-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.62.0.tgz", + "integrity": "sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==", + "requires": { + "@typescript-eslint/utils": "5.62.0" + } + }, + "@typescript-eslint/parser": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "requires": { + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "requires": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "requires": { + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==" + }, + "@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "requires": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "requires": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + } + }, + "@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "requires": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==" + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "@wry/context": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.7.3.tgz", + "integrity": "sha512-Nl8WTesHp89RF803Se9X3IiHjdmLBrIvPMaJkl+rKVJAYyPsz1TEUbu89943HpvujtSJgDUx9W4vZw3K1Mr3sA==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@wry/equality": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.5.6.tgz", + "integrity": "sha512-D46sfMTngaYlrH+OspKf8mIJETntFnf6Hsjb0V41jAXJ7Bx2kB8Rv8RCUujuVWYttFtHkUNp7g+FwxNQAr6mXA==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@wry/trie": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.4.3.tgz", + "integrity": "sha512-I6bHwH0fSf6RqQcnnXLJKhkSXG45MFral3GxPaY4uAl0LYDZM+YDVDAiU9bYwjTuysy1S0IeecWtmq1SZA3M1w==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==" + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "optional": true, + "peer": true + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==" + }, + "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==", + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + } + } + }, + "acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "requires": {} + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "requires": {} + }, + "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==" + }, + "address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==" + }, + "adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "requires": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "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==", + "requires": { + "debug": "4" + } + }, + "agentkeepalive": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", + "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", + "optional": true, + "peer": true, + "requires": { + "debug": "^4.1.0", + "depd": "^2.0.0", + "humanize-ms": "^1.2.1" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "optional": true, + "peer": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "requires": { + "ajv": "^8.0.0" + } + }, + "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, + "requires": { + "string-width": "^4.1.0" + } + }, + "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==", + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==" + }, + "ansi-red": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", + "integrity": "sha512-ewaIr5y+9CUTGFwZfpECUbFlGcC0GCw1oqR9RI6h1gQCd9Aj2GxSckCnPsVJnmfMZbwFYE+leZGASgkWl06Jow==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "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==" + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "optional": true, + "peer": true + }, + "are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "optional": true, + "peer": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "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==", + "requires": { + "dequal": "^2.0.3" + } + }, + "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==", + "requires": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + } + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + }, + "array-includes": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-string": "^1.0.7" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" + }, + "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==", + "requires": { + "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" + } + }, + "array.prototype.findlastindex": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", + "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + } + }, + "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==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "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==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.reduce": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz", + "integrity": "sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + } + }, + "array.prototype.toreversed": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", + "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.tosorted": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz", + "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==", + "requires": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.1.0", + "es-shim-unscopables": "^1.0.2" + } + }, + "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==", + "requires": { + "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" + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "optional": true, + "peer": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + }, + "asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "optional": true, + "peer": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "optional": true, + "peer": true + }, + "ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==" + }, + "async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + }, + "async-foreach": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "integrity": "sha512-VUeSMD8nEGBWaZK4lizI1sf3yEC7pnAQ/mrI7pC2fBz2s/tq5jWWEngTwaf0Gruu/OoXRGLGg1XFqpYBiGTYJA==", + "optional": true, + "peer": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + }, + "autolinker": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-0.28.1.tgz", + "integrity": "sha512-zQAFO1Dlsn69eXaO6+7YZc+v84aquQKbwpzCE3L0stj56ERn9hutFxPopViLjo9G+rWwjozRhgS5KJ25Xy19cQ==", + "requires": { + "gulp-header": "^1.7.1" + } + }, + "autoprefixer": { + "version": "10.4.14", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", + "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", + "requires": { + "browserslist": "^4.21.5", + "caniuse-lite": "^1.0.30001464", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + } + }, + "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==", + "requires": { + "possible-typed-array-names": "^1.0.0" + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "optional": true, + "peer": true + }, + "aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", + "optional": true, + "peer": true + }, + "axe-core": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.2.tgz", + "integrity": "sha512-zIURGIS1E1Q4pcrMjp+nnEh+16G56eG/MUllJH8yEvw7asDo7Ac9uhC9KIH5jzpITueEZolfYglnCGIuSBz39g==" + }, + "axobject-query": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", + "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", + "requires": { + "dequal": "^2.0.3" + } + }, + "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==", + "requires": { + "@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" + }, + "dependencies": { + "@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "requires": { + "@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" + } + }, + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==" + }, + "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==", + "requires": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "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" + } + }, + "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==" + }, + "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==", + "requires": { + "@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" + } + }, + "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==", + "requires": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "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==", + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + } + } + }, + "babel-loader": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.3.0.tgz", + "integrity": "sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==", + "requires": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "requires": {} + }, + "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==" + }, + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "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==", + "requires": { + "@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" + } + }, + "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==", + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + } + }, + "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==", + "requires": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + } + }, + "babel-plugin-named-asset-import": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz", + "integrity": "sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==", + "requires": {} + }, + "babel-plugin-polyfill-corejs2": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.8.tgz", + "integrity": "sha512-OtIuQfafSzpo/LhnJaykc0R/MMnuLSSVjVYy9mHArIZ9qTCSZ6TpWCuEKZYVoN//t8HqBNScHrOtCrIK5IaGLg==", + "requires": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.5.0", + "semver": "^6.3.1" + }, + "dependencies": { + "@babel/helper-define-polyfill-provider": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", + "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "requires": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.2.tgz", + "integrity": "sha512-Cid+Jv1BrY9ReW9lIfNlNpsI53N+FN7gE+f73zLAUbr9C52W4gKLWSByx47pfDJsEysojKArqOtOKZSVIIUTuQ==", + "requires": { + "@babel/helper-define-polyfill-provider": "^0.4.1", + "core-js-compat": "^3.31.0" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz", + "integrity": "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==", + "requires": { + "@babel/helper-define-polyfill-provider": "^0.5.0" + }, + "dependencies": { + "@babel/helper-define-polyfill-provider": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", + "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "requires": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + } + } + } + }, + "babel-plugin-transform-react-remove-prop-types": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", + "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==" + }, + "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==", + "requires": { + "@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" + } + }, + "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==", + "requires": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "babel-preset-react-app": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-10.0.1.tgz", + "integrity": "sha512-b0D9IZ1WhhCWkrTXyFuIIgqGzSkRIH5D5AmB0bXbzYAB1OBAwHcUeyWW2LorutLWF5btNo/N7r/cIdmvvKJlYg==", + "requires": { + "@babel/core": "^7.16.0", + "@babel/plugin-proposal-class-properties": "^7.16.0", + "@babel/plugin-proposal-decorators": "^7.16.4", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.0", + "@babel/plugin-proposal-numeric-separator": "^7.16.0", + "@babel/plugin-proposal-optional-chaining": "^7.16.0", + "@babel/plugin-proposal-private-methods": "^7.16.0", + "@babel/plugin-transform-flow-strip-types": "^7.16.0", + "@babel/plugin-transform-react-display-name": "^7.16.0", + "@babel/plugin-transform-runtime": "^7.16.4", + "@babel/preset-env": "^7.16.4", + "@babel/preset-react": "^7.16.0", + "@babel/preset-typescript": "^7.16.0", + "@babel/runtime": "^7.16.3", + "babel-plugin-macros": "^3.1.0", + "babel-plugin-transform-react-remove-prop-types": "^0.4.24" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "optional": true, + "peer": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bfj": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.0.2.tgz", + "integrity": "sha512-+e/UqUzwmzJamNF50tBV6tZPTORow7gQ96iFow+8b562OdMpEK0BcJEq2OSPEDmAbSMBQ7PKZ87ubFkgxpYWgw==", + "requires": { + "bluebird": "^3.5.5", + "check-types": "^11.1.1", + "hoopy": "^0.1.4", + "tryer": "^1.0.1" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + } + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + } + } + }, + "bonjour-service": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", + "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==", + "requires": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "bootstrap": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", + "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "requires": {} + }, + "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, + "requires": { + "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" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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 + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "requires": { + "fill-range": "^7.1.1" + } + }, + "brotli": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", + "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", + "requires": { + "base64-js": "^1.1.2" + } + }, + "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==" + }, + "browserslist": { + "version": "4.23.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", + "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", + "requires": { + "caniuse-lite": "^1.0.30001640", + "electron-to-chromium": "^1.4.820", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.1.0" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "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==" + }, + "builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==" + }, + "bwip-js": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/bwip-js/-/bwip-js-3.4.3.tgz", + "integrity": "sha512-x+mQE/bq5V0Nlkn4Jd4cktNlEPH4zeIGSOEQNUtsV/cCJNiBba7u/S9PYR1pmD2WDeeZAIbYTjvGHjBQ21RXvw==" + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==" + }, + "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, + "requires": { + "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" + }, + "dependencies": { + "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, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + }, + "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 + } + } + }, + "call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "requires": { + "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" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, + "camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "requires": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==" + }, + "camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "optional": true, + "peer": true, + "requires": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + } + }, + "caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "requires": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001645", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001645.tgz", + "integrity": "sha512-GFtY2+qt91kzyMk6j48dJcwJVq5uTkk71XxE3RtScx7XWRLsO7bU44LOFkOZYR8w9YMS0UhPSYpN/6rAMImmLw==" + }, + "case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "optional": true, + "peer": true + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==" + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, + "check-types": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.2.tgz", + "integrity": "sha512-HBiYvXvn9Z70Z88XKjz3AEKd4HJhBXsa3j7xFnITAzoS8+q6eIGi8qDB8FKPBAjtuxjI/zFpwuiCb8oDtKOYrA==" + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.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" + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "optional": true, + "peer": true + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" + }, + "ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==" + }, + "cjs-module-lexer": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", + "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==" + }, + "classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + }, + "clean-css": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz", + "integrity": "sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==", + "requires": { + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "optional": true, + "peer": true + }, + "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 + }, + "cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dev": true, + "requires": { + "restore-cursor": "^4.0.0" + } + }, + "cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==" + }, + "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, + "requires": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "dependencies": { + "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 + }, + "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 + }, + "string-width": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "dev": true, + "requires": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + } + }, + "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, + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, + "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==" + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==" + }, + "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, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==" + }, + "coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "requires": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + }, + "dependencies": { + "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==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "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==" + }, + "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==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "coffee-script": { + "version": "1.12.7", + "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz", + "integrity": "sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==" + }, + "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==" + }, + "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==", + "requires": { + "color-name": "~1.1.4" + } + }, + "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==" + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "optional": true, + "peer": true + }, + "colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" + }, + "colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true + }, + "common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" + }, + "common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==" + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "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==" + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "requires": { + "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" + } + }, + "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==" + }, + "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==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "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==", + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "requires": { + "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" + } + }, + "confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==" + }, + "connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==" + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "optional": true, + "peer": true + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" + }, + "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==" + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "core-js": { + "version": "3.31.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.31.1.tgz", + "integrity": "sha512-2sKLtfq1eFST7l7v62zaqXacPc7uG8ZAya8ogijLhTtaKNcpzpB4TMoTw2Si+8GYKRwFPMMtUT0263QFWFfqyQ==" + }, + "core-js-compat": { + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.0.tgz", + "integrity": "sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==", + "requires": { + "browserslist": "^4.22.3" + } + }, + "core-js-pure": { + "version": "3.31.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.31.1.tgz", + "integrity": "sha512-w+C62kvWti0EPs4KPMCMVv9DriHSXfQOCQ94bGGBiEW5rrbtt/Rz8n5Krhfw9cpFyzXBjf3DB3QnPdEzGDY4Fw==" + }, + "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==" + }, + "cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "requires": { + "@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" + } + }, + "create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "requires": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "dependencies": { + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==", + "requires": { + "@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" + } + } + } + }, + "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, + "requires": { + "cross-spawn": "^7.0.1" + } + }, + "cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "requires": { + "node-fetch": "^2.6.12" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "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==" + }, + "css-blank-pseudo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", + "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "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==", + "requires": { + "tiny-invariant": "^1.0.6" + } + }, + "css-declaration-sorter": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", + "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", + "requires": {} + }, + "css-has-pseudo": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", + "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "css-loader": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz", + "integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==", + "requires": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.21", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.3", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.8" + } + }, + "css-minimizer-webpack-plugin": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz", + "integrity": "sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==", + "requires": { + "cssnano": "^5.0.6", + "jest-worker": "^27.0.2", + "postcss": "^8.3.5", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "css-prefers-color-scheme": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", + "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", + "requires": {} + }, + "css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + }, + "dependencies": { + "css-what": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==" + }, + "dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + } + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + }, + "dependencies": { + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + } + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "requires": { + "boolbase": "~1.0.0" + } + } + } + }, + "css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" + }, + "css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", + "requires": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" + }, + "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 + }, + "cssdb": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.6.0.tgz", + "integrity": "sha512-Nna7rph8V0jC6+JBY4Vk4ndErUmfJfV6NJCaZdurL0omggabiy+QB2HCQtu5c/ACLZ0I7REv7A4QyPIoYzZx0w==" + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" + }, + "cssnano": { + "version": "5.1.15", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", + "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", + "requires": { + "cssnano-preset-default": "^5.2.14", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + } + }, + "cssnano-preset-default": { + "version": "5.2.14", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "requires": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + } + }, + "cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "requires": {} + }, + "csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "requires": { + "css-tree": "^1.1.2" + }, + "dependencies": { + "css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==" + }, + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" + } + } + }, + "csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "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==", + "requires": { + "lodash.flow": "^3.5.0" + } + }, + "d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "requires": { + "internmap": "1 - 2" + } + }, + "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==" + }, + "d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "requires": { + "delaunator": "5" + } + }, + "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==" + }, + "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==", + "requires": { + "d3-color": "1 - 3" + } + }, + "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==" + }, + "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==", + "requires": { + "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" + } + }, + "d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "requires": { + "d3-path": "^3.1.0" + } + }, + "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==", + "requires": { + "d3-array": "2 - 3" + } + }, + "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==", + "requires": { + "d3-time": "1 - 3" + } + }, + "damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "optional": true, + "peer": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + } + }, + "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==", + "requires": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + } + }, + "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==", + "requires": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + } + }, + "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==", + "requires": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + } + }, + "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==", + "devOptional": true, + "requires": { + "@babel/runtime": "^7.21.0" + } + }, + "dayjs": { + "version": "1.11.11", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", + "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==" + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "optional": true, + "peer": true + }, + "decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "optional": true, + "peer": true, + "requires": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "optional": true, + "peer": true + } + } + }, + "decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" + }, + "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, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "dedent": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "requires": {} + }, + "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 + }, + "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==" + }, + "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==" + }, + "default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "requires": { + "execa": "^5.0.0" + } + }, + "defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "requires": { + "clone": "^1.0.2" + }, + "dependencies": { + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==" + } + } + }, + "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 + }, + "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==", + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + } + }, + "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==" + }, + "define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "requires": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "requires": { + "robust-predicates": "^3.0.2" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "optional": true, + "peer": true + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==" + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "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 + }, + "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==" + }, + "detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "requires": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "dfa": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz", + "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==" + }, + "diacritics-map": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/diacritics-map/-/diacritics-map-0.1.0.tgz", + "integrity": "sha512-3omnDTYrGigU0i4cJjvaKwD52B8aoqyX/NEIkukFFkogBemsIbhSa1O414fpTp5nuszJG6lvQ5vBvDVNCbSsaQ==" + }, + "didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, + "diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==" + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "requires": { + "path-type": "^4.0.0" + } + }, + "dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==" + }, + "dns-packet": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.0.tgz", + "integrity": "sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ==", + "requires": { + "@leichtgewicht/ip-codec": "^2.0.1" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "requires": { + "esutils": "^2.0.2" + } + }, + "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 + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "requires": { + "utila": "~0.4" + } + }, + "dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "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==", + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" + }, + "domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "requires": { + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==" + } + } + }, + "domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "requires": { + "domelementtype": "^2.3.0" + } + }, + "domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "requires": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + } + }, + "dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "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, + "requires": { + "is-obj": "^2.0.0" + } + }, + "dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" + }, + "dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" + }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, + "duplexer3": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", + "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "optional": true, + "peer": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "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==" + }, + "ejs": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", + "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "requires": { + "jake": "^10.8.5" + } + }, + "electron-to-chromium": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz", + "integrity": "sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA==" + }, + "emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==" + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "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, + "requires": { + "iconv-lite": "^0.6.2" + } + }, + "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, + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "optional": true, + "peer": true + }, + "err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "optional": true, + "peer": true + }, + "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==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "requires": { + "stackframe": "^1.3.4" + } + }, + "es-abstract": { + "version": "1.23.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.2.tgz", + "integrity": "sha512-60s3Xv2T2p1ICykc7c+DNDPLDMm9t4QxCOUU0K9JxiLjM3C1zB9YVdN7tjxrFd4+AkZ8CdX1ovUga4P2+1e+/w==", + "requires": { + "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.7", + "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.5", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + } + }, + "es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" + }, + "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==", + "requires": { + "get-intrinsic": "^1.2.4" + } + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + }, + "es-iterator-helpers": { + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz", + "integrity": "sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==", + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "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" + } + }, + "es-module-lexer": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", + "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==" + }, + "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==", + "requires": { + "es-errors": "^1.3.0" + } + }, + "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==", + "requires": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + } + }, + "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==", + "requires": { + "hasown": "^2.0.0" + } + }, + "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==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "requires": { + "@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" + } + }, + "escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==" + }, + "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 + }, + "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==" + }, + "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==" + }, + "escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "source-map": "~0.6.1" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + } + } + }, + "eslint": { + "version": "8.45.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.45.0.tgz", + "integrity": "sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==", + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.1.0", + "@eslint/js": "8.44.0", + "@humanwhocodes/config-array": "^0.11.10", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "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.0", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.6.0", + "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" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "eslint-scope": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.1.tgz", + "integrity": "sha512-CvefSOsDdaYYvxChovdrPo/ZGt8d5lrJWleAc1diXRKhHGiTYEI26cvo8Kle/wGnsizoCJjK73FMg1/IkIwiNA==", + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + }, + "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==", + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "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==", + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "requires": { + "type-fest": "^0.20.2" + } + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + }, + "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==" + }, + "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==", + "requires": { + "p-locate": "^5.0.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "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==", + "requires": { + "p-limit": "^3.0.2" + } + }, + "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==" + } + } + }, + "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, + "requires": {} + }, + "eslint-config-react-app": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", + "integrity": "sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==", + "requires": { + "@babel/core": "^7.16.0", + "@babel/eslint-parser": "^7.16.3", + "@rushstack/eslint-patch": "^1.1.0", + "@typescript-eslint/eslint-plugin": "^5.5.0", + "@typescript-eslint/parser": "^5.5.0", + "babel-preset-react-app": "^10.0.1", + "confusing-browser-globals": "^1.0.11", + "eslint-plugin-flowtype": "^8.0.3", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jest": "^25.3.0", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.27.1", + "eslint-plugin-react-hooks": "^4.3.0", + "eslint-plugin-testing-library": "^5.0.1" + } + }, + "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==", + "requires": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "requires": { + "debug": "^3.2.7" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-plugin-flowtype": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz", + "integrity": "sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==", + "requires": { + "lodash": "^4.17.21", + "string-natural-compare": "^3.0.1" + } + }, + "eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "requires": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "requires": { + "esutils": "^2.0.2" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "eslint-plugin-jest": { + "version": "25.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz", + "integrity": "sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==", + "requires": { + "@typescript-eslint/experimental-utils": "^5.0.0" + } + }, + "eslint-plugin-jsx-a11y": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", + "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", + "requires": { + "@babel/runtime": "^7.20.7", + "aria-query": "^5.1.3", + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.6.2", + "axobject-query": "^3.1.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "has": "^1.0.3", + "jsx-ast-utils": "^3.3.3", + "language-tags": "=1.0.5", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + } + }, + "eslint-plugin-react": { + "version": "7.34.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz", + "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==", + "requires": { + "array-includes": "^3.1.7", + "array.prototype.findlast": "^1.2.4", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.3", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.17", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7", + "object.hasown": "^1.1.3", + "object.values": "^1.1.7", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.10" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "requires": { + "esutils": "^2.0.2" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + }, + "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==", + "requires": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "requires": {} + }, + "eslint-plugin-testing-library": { + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.11.0.tgz", + "integrity": "sha512-ELY7Gefo+61OfXKlQeXNIDVVLPcvKTeiQOoMZG9TeuWa7Ln4dUNRv8JdRWBQI9Mbb427XGlVB1aa1QPZxBJM8Q==", + "requires": { + "@typescript-eslint/utils": "^5.58.0" + } + }, + "eslint-plugin-tsdoc": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.17.tgz", + "integrity": "sha512-xRmVi7Zx44lOBuYqG8vzTXuL6IdGOeF9nHX17bjJ8+VE6fsxpdGem0/SBTmAwgYMKYB1WBkqRJVQ+n8GK041pA==", + "dev": true, + "requires": { + "@microsoft/tsdoc": "0.14.2", + "@microsoft/tsdoc-config": "0.16.2" + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-visitor-keys": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==" + }, + "eslint-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz", + "integrity": "sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==", + "requires": { + "@types/eslint": "^7.29.0 || ^8.4.1", + "jest-worker": "^28.0.2", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0" + }, + "dependencies": { + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "requires": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "requires": { + "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" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==" + }, + "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==", + "requires": { + "fill-range": "^2.1.0" + }, + "dependencies": { + "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==", + "requires": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg==", + "requires": { + "kind-of": "^3.0.2" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "requires": { + "isarray": "1.0.0" + } + }, + "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==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "requires": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "dependencies": { + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==" + }, + "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==", + "requires": { + "@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" + } + } + } + }, + "express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "optional": true, + "peer": true + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "optional": true, + "peer": true + }, + "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==" + }, + "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 + }, + "fast-glob": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz", + "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==", + "requires": { + "@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" + } + }, + "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==" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "requires": { + "reusify": "^1.0.4" + } + }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "requires": { + "bser": "2.1.1" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "requires": { + "escape-string-regexp": "^1.0.5" + }, + "dependencies": { + "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==" + } + } + }, + "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==", + "requires": { + "flat-cache": "^3.0.4" + } + }, + "file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "requires": { + "minimatch": "^5.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "filesize": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", + "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==" + }, + "fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "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, + "requires": { + "findup-sync": "^4.0.0", + "merge": "^2.1.1" + } + }, + "find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "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, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" + } + }, + "flag-icons": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/flag-icons/-/flag-icons-6.7.0.tgz", + "integrity": "sha512-+KXrrrXN2jiETFxisFl+3f83Bq7tj5nuIWnbv9fX59k05lvldEXRCOffybb5hAIjMWt4nmG0E8OfKt7Flm99Eg==" + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" + }, + "follow-redirects": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==" + }, + "fontkit": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.2.tgz", + "integrity": "sha512-jc4k5Yr8iov8QfS6u8w2CnHWVmbOGtdBtOXMze5Y+QD966Rx6PEVWXSEGwXlsDlKtu1G12cJjcsybnqhSk/+LA==", + "requires": { + "@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" + } + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "requires": { + "is-callable": "^1.1.3" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "optional": true, + "peer": true + }, + "fork-ts-checker-webpack-plugin": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", + "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", + "requires": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "chokidar": "^3.4.2", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "requires": {} + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + } + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "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==" + }, + "schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "requires": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" + } + } + }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "optional": true, + "peer": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "fs-monkey": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.4.tgz", + "integrity": "sha512-INM/fWAxMICjttnD0DX1rBvinKskj5G1w+oy/pnm9u/tSlnBrzFonJMcalKJ30P8RRsPzKcCG7Q8l0jx5Fh9YQ==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "optional": true + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "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==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + } + }, + "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==" + }, + "gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "optional": true, + "peer": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + } + }, + "gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "optional": true, + "peer": true, + "requires": { + "globule": "^1.0.0" + } + }, + "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, + "requires": { + "loader-utils": "^3.2.0" + } + }, + "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==" + }, + "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==" + }, + "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 + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" + }, + "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==" + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==", + "optional": true, + "peer": true + }, + "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==" + }, + "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==", + "requires": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + } + }, + "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, + "requires": { + "resolve-pkg-maps": "^1.0.0" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "optional": true, + "peer": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "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" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "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, + "requires": { + "ini": "2.0.0" + }, + "dependencies": { + "ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true + } + } + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "requires": { + "global-prefix": "^3.0.0" + } + }, + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "dependencies": { + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "requires": { + "define-properties": "^1.1.3" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "globule": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.4.tgz", + "integrity": "sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==", + "optional": true, + "peer": true, + "requires": { + "glob": "~7.1.1", + "lodash": "^4.17.21", + "minimatch": "~3.0.2" + }, + "dependencies": { + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "optional": true, + "peer": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "optional": true, + "peer": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "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, + "requires": { + "@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" + }, + "dependencies": { + "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, + "requires": { + "pump": "^3.0.0" + } + } + } + }, + "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==" + }, + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" + }, + "graphql": { + "version": "16.9.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", + "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==" + }, + "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==", + "requires": { + "tslib": "^2.1.0" + } + }, + "graphql-ws": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.16.0.tgz", + "integrity": "sha512-Ju2RCU2dQMgSKtArPbEtsK5gNLnsQyTNIo/T7cZNp96niC1x0KdJNZV0TIoilceBPQwfb5itrGl8pkFeOUMl4A==", + "requires": {} + }, + "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==", + "requires": { + "ansi-red": "^0.1.1", + "coffee-script": "^1.12.4", + "extend-shallow": "^2.0.1", + "js-yaml": "^3.8.1", + "toml": "^2.3.2" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" + } + } + }, + "gulp-header": { + "version": "1.8.12", + "resolved": "https://registry.npmjs.org/gulp-header/-/gulp-header-1.8.12.tgz", + "integrity": "sha512-lh9HLdb53sC7XIZOYzTXM4lFuXElv3EVkSDhsd7DoJBj7hm+Ni7D3qYbb+Rr8DuM8nRanBvkVO9d7askreXGnQ==", + "requires": { + "concat-with-sourcemaps": "*", + "lodash.template": "^4.4.0", + "through2": "^2.0.0" + } + }, + "gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "requires": { + "duplexer": "^0.1.2" + } + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "optional": true, + "peer": true + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "optional": true, + "peer": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "optional": true, + "peer": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "optional": true, + "peer": true + } + } + }, + "hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "optional": true, + "peer": true + }, + "harmony-reflect": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", + "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "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==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "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==", + "requires": { + "es-define-property": "^1.0.0" + } + }, + "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==" + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "requires": { + "has-symbols": "^1.0.3" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "optional": true, + "peer": true + }, + "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 + }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "requires": { + "function-bind": "^1.1.2" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + }, + "history": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz", + "integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==", + "requires": { + "@babel/runtime": "^7.7.6" + } + }, + "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==", + "requires": { + "react-is": "^16.7.0" + }, + "dependencies": { + "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==" + } + } + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hoopy": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", + "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==" + }, + "hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "optional": true, + "peer": true, + "requires": { + "lru-cache": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "peer": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true, + "peer": true + } + } + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "requires": { + "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" + } + }, + "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==" + }, + "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==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "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==", + "requires": { + "whatwg-encoding": "^1.0.5" + } + }, + "html-entities": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", + "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==" + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + }, + "html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "requires": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "dependencies": { + "commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==" + } + } + }, + "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==", + "requires": { + "void-elements": "3.1.0" + } + }, + "html-webpack-plugin": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz", + "integrity": "sha512-6YrDKTuqaP/TquFH7h4srYWsZx+x6k6+FbsTm0ziCwGHDP78Unr1r9F/H4+sGmMbX08GQcJ+K64x55b+7VM/jg==", + "requires": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + } + }, + "htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "devOptional": true + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "dependencies": { + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + } + } + }, + "http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "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==", + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "requires": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "dependencies": { + "is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==" + } + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "optional": true, + "peer": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "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==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "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==" + }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "optional": true, + "peer": true, + "requires": { + "ms": "^2.0.0" + } + }, + "husky": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", + "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "dev": true + }, + "i18next": { + "version": "21.10.0", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.10.0.tgz", + "integrity": "sha512-YeuIBmFsGjUfO3qBmMOc0rQaun4mIpGKET5WDwvu8lU7gvwpcariZLNtL0Fzj+zazcHUrlXHiptcFhBMFaxzfg==", + "requires": { + "@babel/runtime": "^7.17.2" + } + }, + "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==", + "requires": { + "@babel/runtime": "^7.23.2" + } + }, + "i18next-http-backend": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.5.2.tgz", + "integrity": "sha512-+K8HbDfrvc1/2X8jpb7RLhI9ZxBDpx3xogYkQwGKlWAUXLSEGXzgdt3EcUjLlBCdMwdQY+K+EUF6oh8oB6rwHw==", + "requires": { + "cross-fetch": "4.0.0" + } + }, + "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==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "requires": {} + }, + "idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==" + }, + "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==", + "requires": { + "harmony-reflect": "^1.4.6" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==" + }, + "immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==" + }, + "immutable": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", + "devOptional": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "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 + }, + "import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "devOptional": true + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "optional": true, + "peer": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "inquirer": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", + "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", + "requires": { + "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" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "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==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "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==", + "requires": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + } + }, + "internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==" + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "ip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==", + "optional": true, + "peer": true + }, + "ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==" + }, + "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==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "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==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "requires": { + "has-bigints": "^1.0.1" + } + }, + "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==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "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==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "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==" + }, + "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, + "requires": { + "ci-info": "^2.0.0" + }, + "dependencies": { + "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 + } + } + }, + "is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "requires": { + "hasown": "^2.0.0" + } + }, + "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==", + "requires": { + "is-typed-array": "^1.1.13" + } + }, + "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==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" + }, + "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==", + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + }, + "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==", + "requires": { + "call-bind": "^1.0.2" + } + }, + "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==" + }, + "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==" + }, + "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==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "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, + "requires": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + } + }, + "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==" + }, + "is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "optional": true, + "peer": true + }, + "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==" + }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==" + }, + "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==" + }, + "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 + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "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==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "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 + }, + "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==" + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "optional": true, + "peer": true + }, + "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==", + "requires": { + "isobject": "^3.0.1" + } + }, + "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==" + }, + "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==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==" + }, + "is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==" + }, + "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==" + }, + "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==", + "requires": { + "call-bind": "^1.0.7" + } + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "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==", + "requires": { + "which-typed-array": "^1.1.14" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "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==" + }, + "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==" + }, + "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==", + "requires": { + "call-bind": "^1.0.2" + } + }, + "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==", + "requires": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + } + }, + "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 + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "requires": { + "is-docker": "^2.0.0" + } + }, + "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 + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "optional": true, + "peer": true + }, + "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==" + }, + "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==", + "requires": { + "@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" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "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==", + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "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==", + "requires": { + "semver": "^7.5.3" + } + } + } + }, + "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==", + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "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==", + "requires": { + "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" + } + }, + "jake": { + "version": "10.8.7", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", + "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", + "requires": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "requires": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "dependencies": { + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "requires": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "dependencies": { + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==", + "requires": { + "@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" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "requires": { + "yocto-queue": "^0.1.0" + } + } + } + }, + "jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "requires": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "dependencies": { + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==", + "requires": { + "@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" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "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==", + "requires": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "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==" + } + } + } + } + }, + "jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "requires": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "dependencies": { + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==" + }, + "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==", + "requires": { + "@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" + } + }, + "jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "requires": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + } + }, + "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==", + "requires": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "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==" + } + } + } + } + }, + "jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "requires": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==" + }, + "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==", + "requires": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "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" + } + }, + "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==" + }, + "jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "requires": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + } + }, + "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==", + "requires": { + "@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" + } + }, + "jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "requires": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + } + }, + "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==", + "requires": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "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==", + "requires": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "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==" + } + } + }, + "resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==" + } + } + }, + "jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==" + }, + "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==", + "requires": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "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==" + } + } + } + } + }, + "jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "requires": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "dependencies": { + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==" + }, + "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==", + "requires": { + "@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" + } + }, + "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==", + "requires": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "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==" + } + } + } + } + }, + "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==", + "requires": { + "@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" + }, + "dependencies": { + "@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==", + "requires": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + } + }, + "@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==", + "requires": { + "@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" + } + }, + "@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "requires": { + "type-detect": "4.0.8" + } + }, + "@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==", + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==", + "requires": { + "@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" + } + }, + "jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*" + } + }, + "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==", + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "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==" + } + } + }, + "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==" + } + } + }, + "jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "requires": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "dependencies": { + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==", + "requires": { + "@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" + } + } + } + }, + "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==" + }, + "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==", + "requires": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "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" + } + }, + "jest-jasmine2": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "requires": { + "@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" + }, + "dependencies": { + "@jest/console": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "requires": { + "@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" + } + }, + "@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==", + "requires": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + } + }, + "@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==", + "requires": { + "@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" + } + }, + "@jest/globals": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "requires": { + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" + } + }, + "@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==", + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9", + "source-map": "^0.6.0" + } + }, + "@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==", + "requires": { + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "requires": { + "type-detect": "4.0.8" + } + }, + "@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==", + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==" + }, + "expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "requires": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + } + }, + "jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "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==", + "requires": { + "@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" + } + }, + "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==", + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "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==", + "requires": { + "@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" + } + }, + "jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*" + } + }, + "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==", + "requires": { + "@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" + } + }, + "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==", + "requires": { + "@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" + } + }, + "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==", + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "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==" + } + } + }, + "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==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "requires": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "dependencies": { + "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==" + }, + "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==" + }, + "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==", + "requires": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + } + } + } + }, + "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 + }, + "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, + "requires": { + "@jedmao/location": "^3.0.0", + "jest-diff": "^29.6.4" + } + }, + "jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==" + }, + "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==", + "requires": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "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==" + } + } + } + } + }, + "jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "dependencies": { + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==", + "requires": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "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==" + } + } + } + } + }, + "jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "requires": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "dependencies": { + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==", + "requires": { + "@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" + } + } + } + }, + "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==", + "requires": {} + }, + "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, + "requires": { + "@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" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "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==" + }, + "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==", + "requires": { + "@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" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "requires": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "dependencies": { + "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==" + } + } + }, + "jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "requires": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "dependencies": { + "@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "requires": { + "@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" + } + }, + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==" + }, + "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==" + }, + "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==", + "requires": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "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" + } + }, + "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==" + }, + "jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "requires": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + } + }, + "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==", + "requires": { + "@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" + } + }, + "jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "requires": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + } + }, + "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==", + "requires": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "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==", + "requires": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "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==" + } + } + }, + "resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "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==", + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + } + } + }, + "jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "requires": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "dependencies": { + "@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "requires": { + "@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" + } + }, + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==" + }, + "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==" + }, + "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==", + "requires": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "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" + } + }, + "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==" + }, + "jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "requires": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + } + }, + "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==", + "requires": { + "@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" + } + }, + "jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "requires": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + } + }, + "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==", + "requires": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "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==", + "requires": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "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==" + } + } + }, + "resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==" + }, + "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==", + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + } + } + }, + "jest-serializer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", + "requires": { + "@types/node": "*", + "graceful-fs": "^4.2.9" + } + }, + "jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "requires": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "dependencies": { + "@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "requires": { + "@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" + } + }, + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==" + }, + "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==" + }, + "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==", + "requires": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "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" + } + }, + "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==" + }, + "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==", + "requires": { + "@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" + } + }, + "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==", + "requires": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "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==", + "requires": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "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==" + } + } + }, + "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==", + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + } + } + }, + "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==", + "requires": { + "@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" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "jest-validate": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "requires": { + "@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" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==", + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "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==" + } + } + }, + "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==" + } + } + }, + "jest-watch-typeahead": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-2.2.2.tgz", + "integrity": "sha512-+QgOFW4o5Xlgd6jGS5X37i08tuuXNW8X0CV9WNFi+3n8ExCIP+E1melYhvYLjv5fE6D0yyzk74vsSO8I6GqtvQ==", + "requires": { + "ansi-escapes": "^6.0.0", + "chalk": "^5.2.0", + "jest-regex-util": "^29.0.0", + "jest-watcher": "^29.0.0", + "slash": "^5.0.0", + "string-length": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "dependencies": { + "ansi-escapes": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", + "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==" + }, + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" + }, + "chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==" + }, + "char-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.1.tgz", + "integrity": "sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw==" + }, + "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==" + }, + "slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==" + }, + "string-length": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-5.0.1.tgz", + "integrity": "sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==", + "requires": { + "char-regex": "^2.0.0", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, + "jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "requires": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "dependencies": { + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "requires": { + "@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" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==", + "requires": { + "@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" + } + } + } + }, + "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==", + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jiti": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz", + "integrity": "sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==" + }, + "jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true + }, + "js-base64": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", + "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==", + "optional": true, + "peer": true + }, + "js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "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==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "optional": true, + "peer": true + }, + "jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "requires": { + "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" + }, + "dependencies": { + "ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "requires": {} + } + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "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 + }, + "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==" + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "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==" + }, + "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==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "optional": true, + "peer": true + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==" + }, + "jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "optional": true, + "peer": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "jsx-ast-utils": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.4.tgz", + "integrity": "sha512-fX2TVdCViod6HwKEtSWGHs57oFhVfCMwieb9PuRDgjDPh5XeqJiHFFFJCHxU5cnTc3Bu/GRL+kPiFmw8XWOfKw==", + "requires": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + } + }, + "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, + "requires": { + "json-buffer": "3.0.0" + } + }, + "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==" + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + }, + "klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==" + }, + "language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==" + }, + "language-tags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", + "requires": { + "language-subtag-registry": "~0.3.2" + } + }, + "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, + "requires": { + "package-json": "^6.3.0" + } + }, + "launch-editor": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz", + "integrity": "sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==", + "requires": { + "picocolors": "^1.0.0", + "shell-quote": "^1.7.3" + } + }, + "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==", + "requires": { + "set-getter": "^0.1.0" + } + }, + "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==" + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==" + }, + "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==" + }, + "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==", + "peer": true, + "requires": { + "uc.micro": "^2.0.0" + } + }, + "lint-staged": { + "version": "15.2.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.7.tgz", + "integrity": "sha512-+FdVbbCZ+yoh7E/RosSdqKJyUM2OEjTciH0TFNkawKgvFp1zbGlEC39RADg+xKBG1R4mhoH2j85myBQZ5wR+lw==", + "dev": true, + "requires": { + "chalk": "~5.3.0", + "commander": "~12.1.0", + "debug": "~4.3.4", + "execa": "~8.0.1", + "lilconfig": "~3.1.1", + "listr2": "~8.2.1", + "micromatch": "~4.0.7", + "pidtree": "~0.6.0", + "string-argv": "~0.3.2", + "yaml": "~2.4.2" + }, + "dependencies": { + "chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true + }, + "commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true + }, + "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, + "requires": { + "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" + } + }, + "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 + }, + "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 + }, + "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 + }, + "lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true + }, + "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 + }, + "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, + "requires": { + "path-key": "^4.0.0" + } + }, + "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, + "requires": { + "mimic-fn": "^4.0.0" + } + }, + "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 + }, + "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 + }, + "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 + }, + "yaml": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", + "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", + "dev": true + } + } + }, + "list-item": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/list-item/-/list-item-1.1.1.tgz", + "integrity": "sha512-S3D0WZ4J6hyM8o5SNKWaMYB1ALSacPZ2nHGEuCjmHZ+dc03gFeNZoNDcqfcnO4vDhTZmNrqrpYZCdXsRh22bzw==", + "requires": { + "expand-range": "^1.8.1", + "extend-shallow": "^2.0.1", + "is-number": "^2.1.0", + "repeat-string": "^1.5.2" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg==", + "requires": { + "kind-of": "^3.0.2" + } + }, + "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==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "listr2": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.1.tgz", + "integrity": "sha512-irTfvpib/rNiD637xeevjO2l3Z5loZmuaRi0L0YE5LfijwVY96oyVn0DFD3o/teAok7nfobMG1THvvcHh/BP6g==", + "dev": true, + "requires": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.0.0", + "rfdc": "^1.3.1", + "wrap-ansi": "^9.0.0" + }, + "dependencies": { + "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 + }, + "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 + }, + "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 + }, + "eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true + }, + "string-width": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "dev": true, + "requires": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + } + }, + "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, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "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, + "requires": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + } + } + } + }, + "loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==" + }, + "loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==" + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "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==" + }, + "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 + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "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==" + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, + "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==" + }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" + }, + "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==", + "requires": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "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==", + "requires": { + "lodash._reinterpolate": "^3.0.0" + } + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" + }, + "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==", + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "log-update": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.0.0.tgz", + "integrity": "sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==", + "dev": true, + "requires": { + "ansi-escapes": "^6.2.0", + "cli-cursor": "^4.0.0", + "slice-ansi": "^7.0.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", + "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", + "dev": true + }, + "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 + }, + "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 + }, + "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 + }, + "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, + "requires": { + "get-east-asian-width": "^1.0.0" + } + }, + "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, + "requires": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + } + }, + "string-width": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "dev": true, + "requires": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + } + }, + "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, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "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, + "requires": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + } + } + } + }, + "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==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "requires": { + "tslib": "^2.0.3" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "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==", + "requires": { + "yallist": "^3.0.2" + } + }, + "lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "peer": true + }, + "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 + }, + "magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "requires": { + "sourcemap-codec": "^1.4.8" + } + }, + "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==", + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "requires": { + "tmpl": "1.0.5" + } + }, + "map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "optional": true, + "peer": true + }, + "markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "peer": true, + "requires": { + "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" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "peer": true + } + } + }, + "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==" + }, + "markdown-toc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/markdown-toc/-/markdown-toc-1.2.0.tgz", + "integrity": "sha512-eOsq7EGd3asV0oBfmyqngeEIhrbkc7XVP63OwcJBIhH2EpG2PzFcbZdhy1jutXSlRBBVMNXHvMtSr5LAxSUvUg==", + "requires": { + "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" + } + }, + "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==" + }, + "mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==" + }, + "mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "peer": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + }, + "memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "requires": { + "fs-monkey": "^1.0.4" + } + }, + "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==" + }, + "meow": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", + "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", + "optional": true, + "peer": true, + "requires": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize": "^1.2.0", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "dependencies": { + "type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "optional": true, + "peer": true + } + } + }, + "merge": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", + "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", + "dev": true + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "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==" + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + }, + "micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "requires": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "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==", + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "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 + }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "devOptional": true + }, + "mini-css-extract-plugin": { + "version": "2.7.6", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz", + "integrity": "sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw==", + "requires": { + "schema-utils": "^4.0.0" + }, + "dependencies": { + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + } + } + }, + "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==" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" + }, + "minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "optional": true, + "peer": true, + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + } + }, + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "optional": true, + "peer": true, + "requires": { + "yallist": "^4.0.0" + }, + "dependencies": { + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true, + "peer": true + } + } + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "optional": true, + "peer": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "optional": true, + "peer": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "optional": true, + "peer": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "optional": true, + "peer": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "optional": true, + "peer": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "dependencies": { + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true, + "peer": true + } + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "optional": true, + "peer": true + }, + "mrmime": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "requires": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + } + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, + "mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "requires": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", + "optional": true, + "peer": true + }, + "nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" + }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==" + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "requires": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "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==", + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "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==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } + }, + "node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" + }, + "node-gyp": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "optional": true, + "peer": true, + "requires": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "dependencies": { + "@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "optional": true, + "peer": true, + "requires": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "optional": true, + "peer": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "optional": true, + "peer": true, + "requires": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "peer": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "optional": true, + "peer": true, + "requires": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + } + }, + "minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "optional": true, + "peer": true, + "requires": { + "encoding": "^0.1.12", + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + } + }, + "socks-proxy-agent": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", + "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "optional": true, + "peer": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + } + }, + "ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "optional": true, + "peer": true, + "requires": { + "minipass": "^3.1.1" + } + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "optional": true, + "peer": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "optional": true, + "peer": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true, + "peer": true + } + } + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" + }, + "node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + }, + "node-sass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-7.0.3.tgz", + "integrity": "sha512-8MIlsY/4dXUkJDYht9pIWBhMil3uHmE8b/AdJPjmFn1nBx9X9BASzfzmsCy0uCCb8eqI3SYYzVPDswWqSx7gjw==", + "optional": true, + "peer": true, + "requires": { + "async-foreach": "^0.1.3", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "gaze": "^1.0.0", + "get-stdin": "^4.0.1", + "glob": "^7.0.3", + "lodash": "^4.17.15", + "meow": "^9.0.0", + "nan": "^2.13.2", + "node-gyp": "^8.4.1", + "npmlog": "^5.0.0", + "request": "^2.88.0", + "sass-graph": "^4.0.1", + "stdout-stream": "^1.4.0", + "true-case-path": "^1.0.2" + }, + "dependencies": { + "are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "optional": true, + "peer": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "optional": true, + "peer": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "optional": true, + "peer": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + } + }, + "npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "optional": true, + "peer": true, + "requires": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + } + } + }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "optional": true, + "peer": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "optional": true, + "peer": true, + "requires": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==" + }, + "normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==" + }, + "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==", + "requires": { + "path-key": "^3.0.0" + } + }, + "npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "optional": true, + "peer": true, + "requires": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + } + }, + "nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "requires": { + "boolbase": "^1.0.0" + } + }, + "nwsapi": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz", + "integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==" + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "optional": true, + "peer": true + }, + "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==" + }, + "object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==" + }, + "object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "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==", + "requires": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + } + }, + "object.fromentries": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.6.tgz", + "integrity": "sha512-lq+61g26E/BgHv0ZTFgRvi7NMEPuAxLkFU7rukXjc/AlwH4Am5xXVnIXy3un1bg/JPbXHrixRkK1itUzzPiIjQ==", + "requires": { + "array.prototype.reduce": "^1.0.5", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.21.2", + "safe-array-concat": "^1.0.0" + } + }, + "object.groupby": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", + "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1" + } + }, + "object.hasown": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", + "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", + "requires": { + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + } + }, + "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==", + "requires": { + "isobject": "^3.0.1" + } + }, + "object.values": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "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, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "optimism": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.16.2.tgz", + "integrity": "sha512-zWNbgWj+3vLEjZNIh/okkY2EUfX+vB9TJopzIZwT1xxaMqC5hRLLraePod4c5n4He08xuXNH+zhKFFCu390wiQ==", + "requires": { + "@wry/context": "^0.7.0", + "@wry/trie": "^0.3.0" + }, + "dependencies": { + "@wry/trie": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.3.2.tgz", + "integrity": "sha512-yRTyhWSls2OY/pYLfwff867r8ekooZ4UI+/gxot5Wj8EFwSf2rG+n+Mo/6LoLQm1TKA4GRj2+LCpbfS937dClQ==", + "requires": { + "tslib": "^2.3.0" + } + } + } + }, + "optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "requires": { + "@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" + } + }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "requires": { + "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" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + } + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==" + }, + "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 + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "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==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "optional": true, + "peer": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "requires": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "dependencies": { + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==" + } + } + }, + "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==" + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "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==", + "requires": { + "callsites": "^3.0.0" + } + }, + "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==", + "requires": { + "@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" + } + }, + "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 + }, + "parse-srcset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", + "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==" + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "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==" + }, + "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==" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "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==" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" + }, + "picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, + "pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==" + }, + "pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==" + }, + "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==", + "requires": { + "find-up": "^4.0.0" + } + }, + "pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "requires": { + "find-up": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==" + } + } + }, + "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==" + }, + "postcss": { + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", + "requires": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "postcss-attribute-case-insensitive": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz", + "integrity": "sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==", + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-browser-comments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-4.0.0.tgz", + "integrity": "sha512-X9X9/WN3KIvY9+hNERUqX9gncsgBA25XaeR+jshHz2j8+sYyHktHw1JdKuMjeLpGktXidqDhA7b/qm1mrBDmgg==", + "requires": {} + }, + "postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "requires": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-clamp": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", + "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-color-functional-notation": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", + "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-color-hex-alpha": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz", + "integrity": "sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-color-rebeccapurple": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz", + "integrity": "sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-colormin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", + "requires": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-convert-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "requires": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-custom-media": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz", + "integrity": "sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-custom-properties": { + "version": "12.1.11", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz", + "integrity": "sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-custom-selectors": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz", + "integrity": "sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==", + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-dir-pseudo-class": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz", + "integrity": "sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==", + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-discard-comments": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "requires": {} + }, + "postcss-discard-duplicates": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "requires": {} + }, + "postcss-discard-empty": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "requires": {} + }, + "postcss-discard-overridden": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "requires": {} + }, + "postcss-double-position-gradients": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz", + "integrity": "sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==", + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-env-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", + "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-flexbugs-fixes": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-5.0.2.tgz", + "integrity": "sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==", + "requires": {} + }, + "postcss-focus-visible": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", + "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "postcss-focus-within": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", + "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "postcss-font-variant": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "requires": {} + }, + "postcss-gap-properties": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", + "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", + "requires": {} + }, + "postcss-image-set-function": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz", + "integrity": "sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "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, + "requires": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + } + }, + "postcss-initial": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", + "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", + "requires": {} + }, + "postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "requires": { + "camelcase-css": "^2.0.1" + } + }, + "postcss-lab-function": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz", + "integrity": "sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==", + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "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==", + "requires": { + "lilconfig": "^2.0.5", + "yaml": "^2.1.1" + }, + "dependencies": { + "yaml": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", + "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==" + } + } + }, + "postcss-loader": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", + "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", + "requires": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.5" + } + }, + "postcss-logical": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", + "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", + "requires": {} + }, + "postcss-media-minmax": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", + "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "requires": {} + }, + "postcss-merge-longhand": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "requires": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + } + }, + "postcss-merge-rules": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", + "requires": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + } + }, + "postcss-minify-font-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-minify-gradients": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "requires": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-minify-params": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "requires": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-minify-selectors": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "requires": { + "postcss-selector-parser": "^6.0.5" + } + }, + "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, + "requires": { + "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" + } + }, + "postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "requires": {} + }, + "postcss-modules-local-by-default": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", + "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", + "requires": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "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==", + "requires": { + "icss-utils": "^5.0.0" + } + }, + "postcss-nested": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", + "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "requires": { + "postcss-selector-parser": "^6.0.11" + } + }, + "postcss-nesting": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", + "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", + "requires": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-normalize": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize/-/postcss-normalize-10.0.1.tgz", + "integrity": "sha512-+5w18/rDev5mqERcG3W5GZNMJa1eoYYNGo8gB7tEwaos0ajk3ZXAI4mHGcNT47NE+ZnZD1pEpUOFLvltIwmeJA==", + "requires": { + "@csstools/normalize.css": "*", + "postcss-browser-comments": "^4", + "sanitize.css": "*" + } + }, + "postcss-normalize-charset": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "requires": {} + }, + "postcss-normalize-display-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-positions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-repeat-style": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-string": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-timing-functions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-unicode": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "requires": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "requires": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-whitespace": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-opacity-percentage": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.3.tgz", + "integrity": "sha512-An6Ba4pHBiDtyVpSLymUUERMo2cU7s+Obz6BTrS+gxkbnSBNKSuD0AVUc+CpBMrpVPKKfoVz0WQCX+Tnst0i4A==", + "requires": {} + }, + "postcss-ordered-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "requires": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-overflow-shorthand": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", + "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-page-break": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "requires": {} + }, + "postcss-place": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", + "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-preset-env": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.8.3.tgz", + "integrity": "sha512-T1LgRm5uEVFSEF83vHZJV2z19lHg4yJuZ6gXZZkqVsqv63nlr6zabMH3l4Pc01FQCyfWVrh2GaUeCVy9Po+Aag==", + "requires": { + "@csstools/postcss-cascade-layers": "^1.1.1", + "@csstools/postcss-color-function": "^1.1.1", + "@csstools/postcss-font-format-keywords": "^1.0.1", + "@csstools/postcss-hwb-function": "^1.0.2", + "@csstools/postcss-ic-unit": "^1.0.1", + "@csstools/postcss-is-pseudo-class": "^2.0.7", + "@csstools/postcss-nested-calc": "^1.0.0", + "@csstools/postcss-normalize-display-values": "^1.0.1", + "@csstools/postcss-oklab-function": "^1.1.1", + "@csstools/postcss-progressive-custom-properties": "^1.3.0", + "@csstools/postcss-stepped-value-functions": "^1.0.1", + "@csstools/postcss-text-decoration-shorthand": "^1.0.0", + "@csstools/postcss-trigonometric-functions": "^1.0.2", + "@csstools/postcss-unset-value": "^1.0.2", + "autoprefixer": "^10.4.13", + "browserslist": "^4.21.4", + "css-blank-pseudo": "^3.0.3", + "css-has-pseudo": "^3.0.4", + "css-prefers-color-scheme": "^6.0.3", + "cssdb": "^7.1.0", + "postcss-attribute-case-insensitive": "^5.0.2", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^4.2.4", + "postcss-color-hex-alpha": "^8.0.4", + "postcss-color-rebeccapurple": "^7.1.1", + "postcss-custom-media": "^8.0.2", + "postcss-custom-properties": "^12.1.10", + "postcss-custom-selectors": "^6.0.3", + "postcss-dir-pseudo-class": "^6.0.5", + "postcss-double-position-gradients": "^3.1.2", + "postcss-env-function": "^4.0.6", + "postcss-focus-visible": "^6.0.4", + "postcss-focus-within": "^5.0.4", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^3.0.5", + "postcss-image-set-function": "^4.0.7", + "postcss-initial": "^4.0.1", + "postcss-lab-function": "^4.2.1", + "postcss-logical": "^5.0.4", + "postcss-media-minmax": "^5.0.0", + "postcss-nesting": "^10.2.0", + "postcss-opacity-percentage": "^1.1.2", + "postcss-overflow-shorthand": "^3.0.4", + "postcss-page-break": "^3.0.4", + "postcss-place": "^7.0.5", + "postcss-pseudo-class-any-link": "^7.1.6", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^6.0.1", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-pseudo-class-any-link": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", + "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-reduce-initial": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", + "requires": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + } + }, + "postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-replace-overflow-wrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "requires": {} + }, + "postcss-selector-not": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz", + "integrity": "sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==", + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-selector-parser": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "requires": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + }, + "css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + }, + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "requires": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + } + } + } + }, + "postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "requires": { + "postcss-selector-parser": "^6.0.5" + } + }, + "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==" + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" + }, + "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 + }, + "prettier": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==" + }, + "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, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==" + }, + "pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "requires": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "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, + "requires": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + } + }, + "@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, + "requires": { + "@types/yargs-parser": "*" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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 + } + } + }, + "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==" + }, + "promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "requires": { + "asap": "~2.0.6" + } + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "optional": true, + "peer": true + }, + "promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "optional": true, + "peer": true, + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + }, + "dependencies": { + "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==" + } + } + }, + "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==", + "requires": { + "react-is": "^16.3.2", + "warning": "^4.0.0" + }, + "dependencies": { + "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==" + } + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "dependencies": { + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + } + } + }, + "psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, + "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, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" + }, + "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==", + "peer": true + }, + "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, + "requires": { + "escape-goat": "^2.0.0" + } + }, + "pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==" + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==" + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "optional": true, + "peer": true + }, + "raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "requires": { + "performance-now": "^2.1.0" + } + }, + "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==" + }, + "randomatic": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", + "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", + "requires": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, + "dependencies": { + "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==" + } + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true + } + } + }, + "react": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "react-app-polyfill": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz", + "integrity": "sha512-sZ41cxiU5llIB003yxxQBYrARBqe0repqPTTYBTmMqTz9szeBbE37BehCE891NZsmdZqqP+xWKdT3eo3vOzN8w==", + "requires": { + "core-js": "^3.19.2", + "object-assign": "^4.1.1", + "promise": "^8.1.0", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.9", + "whatwg-fetch": "^3.6.2" + } + }, + "react-app-rewired": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/react-app-rewired/-/react-app-rewired-2.2.1.tgz", + "integrity": "sha512-uFQWTErXeLDrMzOJHKp0h8P1z0LV9HzPGsJ6adOtGlA/B9WfT6Shh4j2tLTTGlXOfiVx6w6iWpp7SOC5pvk+gA==", + "requires": { + "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" + } + } + }, + "react-async-script": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/react-async-script/-/react-async-script-1.2.0.tgz", + "integrity": "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==", + "requires": { + "hoist-non-react-statics": "^3.3.0", + "prop-types": "^15.5.0" + } + }, + "react-beautiful-dnd": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.1.tgz", + "integrity": "sha512-0Lvs4tq2VcrEjEgDXHjT98r+63drkKEgqyxdA7qD3mvKwga6a5SscbdLPO2IExotU1jW8L0Ksdl0Cj2AF67nPQ==", + "requires": { + "@babel/runtime": "^7.9.2", + "css-box-model": "^1.2.0", + "memoize-one": "^5.1.1", + "raf-schd": "^4.0.2", + "react-redux": "^7.2.0", + "redux": "^4.0.4", + "use-memo-one": "^1.1.1" + } + }, + "react-bootstrap": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.8.0.tgz", + "integrity": "sha512-e/aNtxl0Z2ozrIaR82jr6Zz7ss9GSoaXpQaxmvtDUsTZIq/XalkduR/ZXP6vbQHz2T4syvjA+4FbtwELxxmpww==", + "requires": { + "@babel/runtime": "^7.21.0", + "@restart/hooks": "^0.4.9", + "@restart/ui": "^1.6.3", + "@types/react-transition-group": "^4.4.5", + "classnames": "^2.3.2", + "dom-helpers": "^5.2.1", + "invariant": "^2.2.4", + "prop-types": "^15.8.1", + "prop-types-extra": "^1.1.0", + "react-transition-group": "^4.4.5", + "uncontrollable": "^7.2.1", + "warning": "^4.0.3" + } + }, + "react-datepicker": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-7.3.0.tgz", + "integrity": "sha512-EqRKLAtLZUTztiq6a+tjSjQX9ES0Xd229JPckAtyZZ4GoY3rtvNWAzkYZnQUf6zTWT50Ki0+t+W9VRQIkSJLfg==", + "requires": { + "@floating-ui/react": "^0.26.2", + "clsx": "^2.1.0", + "date-fns": "^3.3.1", + "prop-types": "^15.7.2", + "react-onclickoutside": "^6.13.0" + }, + "dependencies": { + "clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==" + }, + "date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==" + } + } + }, + "react-dev-utils": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", + "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", + "requires": { + "@babel/code-frame": "^7.16.0", + "address": "^1.1.2", + "browserslist": "^4.18.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "detect-port-alt": "^1.1.6", + "escape-string-regexp": "^4.0.0", + "filesize": "^8.0.6", + "find-up": "^5.0.0", + "fork-ts-checker-webpack-plugin": "^6.5.0", + "global-modules": "^2.0.0", + "globby": "^11.0.4", + "gzip-size": "^6.0.0", + "immer": "^9.0.7", + "is-root": "^2.1.0", + "loader-utils": "^3.2.0", + "open": "^8.4.0", + "pkg-up": "^3.1.0", + "prompts": "^2.4.2", + "react-error-overlay": "^6.0.11", + "recursive-readdir": "^2.2.2", + "shell-quote": "^1.7.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==", + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "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==", + "requires": { + "p-locate": "^5.0.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "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==", + "requires": { + "p-limit": "^3.0.2" + } + } + } + }, + "react-dom": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + } + }, + "react-error-overlay": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", + "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" + }, + "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==", + "dev": true + }, + "react-google-recaptcha": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-3.1.0.tgz", + "integrity": "sha512-cYW2/DWas8nEKZGD7SCu9BSuVz8iOcOLHChHyi7upUuVhkpkhYG/6N3KDiTQ3XAiZ2UAZkfvYKMfAHOzBOcGEg==", + "requires": { + "prop-types": "^15.5.0", + "react-async-script": "^1.2.0" + } + }, + "react-i18next": { + "version": "11.18.6", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.18.6.tgz", + "integrity": "sha512-yHb2F9BiT0lqoQDt8loZ5gWP331GwctHz9tYQ8A2EIEUu+CcEdjBLQWli1USG3RdWQt3W+jqQLg/d4rrQR96LA==", + "requires": { + "@babel/runtime": "^7.14.5", + "html-parse-stringify": "^3.0.1" + } + }, + "react-icons": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.2.1.tgz", + "integrity": "sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==", + "requires": {} + }, + "react-infinite-scroll-component": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-infinite-scroll-component/-/react-infinite-scroll-component-6.1.0.tgz", + "integrity": "sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ==", + "requires": { + "throttle-debounce": "^2.1.0" + } + }, + "react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" + }, + "react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "react-multi-carousel": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/react-multi-carousel/-/react-multi-carousel-2.8.5.tgz", + "integrity": "sha512-C5DAvJkfzR2JK9YixZ3oyF9x6R4LW6nzTpIXrl9Oujxi4uqP9SzVVCjl+JLM3tSdqdjAx/oWZK3dTVBSR73Q+w==" + }, + "react-onclickoutside": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.13.0.tgz", + "integrity": "sha512-ty8So6tcUpIb+ZE+1HAhbLROvAIJYyJe/1vRrrcmW+jLsaM+/powDRqxzo6hSh9CuRZGSL1Q8mvcF5WRD93a0A==", + "requires": {} + }, + "react-popper": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz", + "integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==", + "dev": true, + "requires": { + "react-fast-compare": "^3.0.1", + "warning": "^4.0.2" + } + }, + "react-redux": { + "version": "7.2.9", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", + "integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==", + "requires": { + "@babel/runtime": "^7.15.4", + "@types/react-redux": "^7.1.20", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^17.0.2" + }, + "dependencies": { + "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==" + } + } + }, + "react-refresh": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", + "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==" + }, + "react-router": { + "version": "6.25.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.25.1.tgz", + "integrity": "sha512-u8ELFr5Z6g02nUtpPAggP73Jigj1mRePSwhS/2nkTrlPU5yEkH1vYzWNyvSnSzeeE2DNqWdH+P8OhIh9wuXhTw==", + "requires": { + "@remix-run/router": "1.18.0" + } + }, + "react-router-dom": { + "version": "6.25.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.25.1.tgz", + "integrity": "sha512-0tUDpbFvk35iv+N89dWNrJp+afLgd+y4VtorJZuOCXK0kkCWjEvb3vTJM++SYvMEpbVwXKf3FjeVveVEb6JpDQ==", + "requires": { + "@remix-run/router": "1.18.0", + "react-router": "6.25.1" + } + }, + "react-scripts": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", + "integrity": "sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==", + "requires": { + "@babel/core": "^7.16.0", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", + "@svgr/webpack": "^5.5.0", + "babel-jest": "^27.4.2", + "babel-loader": "^8.2.3", + "babel-plugin-named-asset-import": "^0.3.8", + "babel-preset-react-app": "^10.0.1", + "bfj": "^7.0.2", + "browserslist": "^4.18.1", + "camelcase": "^6.2.1", + "case-sensitive-paths-webpack-plugin": "^2.4.0", + "css-loader": "^6.5.1", + "css-minimizer-webpack-plugin": "^3.2.0", + "dotenv": "^10.0.0", + "dotenv-expand": "^5.1.0", + "eslint": "^8.3.0", + "eslint-config-react-app": "^7.0.1", + "eslint-webpack-plugin": "^3.1.1", + "file-loader": "^6.2.0", + "fs-extra": "^10.0.0", + "fsevents": "^2.3.2", + "html-webpack-plugin": "^5.5.0", + "identity-obj-proxy": "^3.0.0", + "jest": "^27.4.3", + "jest-resolve": "^27.4.2", + "jest-watch-typeahead": "^1.0.0", + "mini-css-extract-plugin": "^2.4.5", + "postcss": "^8.4.4", + "postcss-flexbugs-fixes": "^5.0.2", + "postcss-loader": "^6.2.1", + "postcss-normalize": "^10.0.1", + "postcss-preset-env": "^7.0.1", + "prompts": "^2.4.2", + "react-app-polyfill": "^3.0.0", + "react-dev-utils": "^12.0.1", + "react-refresh": "^0.11.0", + "resolve": "^1.20.0", + "resolve-url-loader": "^4.0.0", + "sass-loader": "^12.3.0", + "semver": "^7.3.5", + "source-map-loader": "^3.0.0", + "style-loader": "^3.3.1", + "tailwindcss": "^3.0.2", + "terser-webpack-plugin": "^5.2.5", + "webpack": "^5.64.4", + "webpack-dev-server": "^4.6.0", + "webpack-manifest-plugin": "^4.0.2", + "workbox-webpack-plugin": "^6.4.1" + }, + "dependencies": { + "@jest/console": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "requires": { + "@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" + } + }, + "@jest/core": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "requires": { + "@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" + } + }, + "@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==", + "requires": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + } + }, + "@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==", + "requires": { + "@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" + } + }, + "@jest/globals": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "requires": { + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" + } + }, + "@jest/reporters": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "requires": { + "@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" + } + }, + "@jest/schemas": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "requires": { + "@sinclair/typebox": "^0.24.1" + } + }, + "@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==", + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9", + "source-map": "^0.6.0" + } + }, + "@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==", + "requires": { + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@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==", + "requires": { + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" + } + }, + "@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + }, + "@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "requires": { + "type-detect": "4.0.8" + } + }, + "@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==", + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "babel-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "requires": { + "@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" + } + }, + "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==", + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + } + }, + "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==", + "requires": { + "babel-plugin-jest-hoist": "^27.5.1", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==" + }, + "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==" + }, + "emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==" + }, + "expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "requires": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + } + }, + "jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", + "requires": { + "@jest/core": "^27.5.1", + "import-local": "^3.0.2", + "jest-cli": "^27.5.1" + } + }, + "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==", + "requires": { + "@jest/types": "^27.5.1", + "execa": "^5.0.0", + "throat": "^6.0.1" + } + }, + "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==", + "requires": { + "@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" + } + }, + "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==", + "requires": { + "@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" + } + }, + "jest-config": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "requires": { + "@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" + } + }, + "jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-docblock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "requires": { + "detect-newline": "^3.0.0" + } + }, + "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==", + "requires": { + "@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" + } + }, + "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==", + "requires": { + "@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" + } + }, + "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==", + "requires": { + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "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==", + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "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==", + "requires": { + "@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" + } + }, + "jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*" + } + }, + "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==", + "requires": { + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" + } + }, + "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==", + "requires": { + "@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" + } + }, + "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==", + "requires": { + "@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" + } + }, + "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==", + "requires": { + "@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" + } + }, + "jest-watch-typeahead": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-1.1.0.tgz", + "integrity": "sha512-Va5nLSJTN7YFtC2jd+7wsoe1pNe5K4ShLux/E5iHEwlB9AxaxmggY7to9KUqKojhaJw3aXqt5WAb4jGPOolpEw==", + "requires": { + "ansi-escapes": "^4.3.1", + "chalk": "^4.0.0", + "jest-regex-util": "^28.0.0", + "jest-watcher": "^28.0.0", + "slash": "^4.0.0", + "string-length": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "dependencies": { + "@jest/console": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", + "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", + "requires": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "slash": "^3.0.0" + }, + "dependencies": { + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + } + } + }, + "@jest/test-result": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", + "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", + "requires": { + "@jest/console": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/types": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "requires": { + "@jest/schemas": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "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==" + }, + "emittery": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==" + }, + "jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "dependencies": { + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + } + } + }, + "jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==" + }, + "jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "requires": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, + "jest-watcher": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", + "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", + "requires": { + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^28.1.3", + "string-length": "^4.0.1" + }, + "dependencies": { + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "requires": { + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + } + }, + "react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" + }, + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==" + }, + "string-length": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-5.0.1.tgz", + "integrity": "sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==", + "requires": { + "char-regex": "^2.0.0", + "strip-ansi": "^7.0.1" + }, + "dependencies": { + "char-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.1.tgz", + "integrity": "sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw==" + } + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "requires": { + "ansi-regex": "^6.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" + } + } + } + } + }, + "jest-watcher": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", + "requires": { + "@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" + } + }, + "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==", + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "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==" + } + } + }, + "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==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "v8-to-istanbul": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==" + } + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + } + } + }, + "react-toastify": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.3.tgz", + "integrity": "sha512-fPfb8ghtn/XMxw3LkxQBk3IyagNpF/LIKjOBflbexr2AWxAH1MJgvnESwEwBn9liLFXgTKWgBSdZpw9m4OTHTg==", + "requires": { + "clsx": "^1.1.1" + } + }, + "react-tooltip": { + "version": "5.27.1", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.27.1.tgz", + "integrity": "sha512-a+micPXcMOMt11CYlwJD4XShcqGziasHco4NPe1OFw298WBTILMyzUgNC1LAFViAe791JdHNVSJIpzhZm2MvDA==", + "requires": { + "@floating-ui/dom": "^1.6.1", + "classnames": "^2.3.0" + } + }, + "react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + }, + "read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "requires": { + "pify": "^2.3.0" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "optional": true, + "peer": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "optional": true, + "peer": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "optional": true, + "peer": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "optional": true, + "peer": true + }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "optional": true, + "peer": true + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "optional": true, + "peer": true, + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "optional": true, + "peer": true + } + } + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "requires": { + "picomatch": "^2.2.1" + } + }, + "recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "requires": { + "minimatch": "^3.0.5" + } + }, + "redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "devOptional": true, + "requires": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + } + }, + "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==", + "requires": { + "@babel/runtime": "^7.9.2" + } + }, + "redux-thunk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", + "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", + "requires": {} + }, + "reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + } + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "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==", + "requires": { + "regenerate": "^1.4.2" + } + }, + "regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==" + }, + "regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "requires": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + } + }, + "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==", + "requires": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + } + }, + "registry-auth-token": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", + "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", + "dev": true, + "requires": { + "rc": "1.2.8" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==" + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==" + }, + "remarkable": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/remarkable/-/remarkable-1.7.4.tgz", + "integrity": "sha512-e6NKUXgX95whv7IgddywbeN/ItCkWbISmc2DiqHJb0wTrqZIexqdco5b8Z3XZoo/48IdNVKM9ZCvTPJ4F5uvhg==", + "requires": { + "argparse": "^1.0.10", + "autolinker": "~0.28.0" + } + }, + "renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "requires": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + } + } + }, + "repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==" + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "optional": true, + "peer": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "optional": true, + "peer": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "optional": true, + "peer": true + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "optional": true, + "peer": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "optional": true, + "peer": true + } + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "reselect": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", + "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" + }, + "resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "requires": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "requires": { + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + } + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "dependencies": { + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + }, + "resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true + }, + "resolve-url-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz", + "integrity": "sha512-05VEMczVREcbtT7Bz+C+96eUO5HDNvdthIiMB34t7FcF8ehcu4wC0sSgPUubs3XW2Q3CNLJk/BJrCU9wVRymiA==", + "requires": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^7.0.35", + "source-map": "0.6.1" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" + }, + "postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "requires": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "resolve.exports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz", + "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==" + }, + "response-iterator": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/response-iterator/-/response-iterator-0.2.6.tgz", + "integrity": "sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw==" + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "restructure": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.0.tgz", + "integrity": "sha512-Xj8/MEIhhfj9X2rmD9iJ4Gga9EFqVlpMj3vfLnV2r/Mh5jRMryNV+6lWh9GdJtDBcBSPIqzRdfBQ3wDtNFv/uw==" + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "optional": true, + "peer": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + }, + "rfdc": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", + "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + }, + "rollup": { + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "requires": { + "fsevents": "~2.3.2" + } + }, + "rollup-plugin-terser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", + "requires": { + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" + }, + "dependencies": { + "jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + } + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "requires": { + "randombytes": "^2.1.0" + } + } + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==" + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "requires": { + "tslib": "^2.1.0" + } + }, + "safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "requires": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "requires": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sanitize-html": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.13.0.tgz", + "integrity": "sha512-Xff91Z+4Mz5QiNSLdLWwjgBDm5b1RU6xBT0+12rapjiaR7SwfRdjw8f+6Rir2MXKLrDicRFHdb51hGOAxmsUIA==", + "requires": { + "deepmerge": "^4.2.2", + "escape-string-regexp": "^4.0.0", + "htmlparser2": "^8.0.0", + "is-plain-object": "^5.0.0", + "parse-srcset": "^1.0.2", + "postcss": "^8.3.11" + }, + "dependencies": { + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" + } + } + }, + "sanitize.css": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", + "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==" + }, + "sass": { + "version": "1.77.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.4.tgz", + "integrity": "sha512-vcF3Ckow6g939GMA4PeU7b2K/9FALXk2KF9J87txdHzXbUF9XRQRwSxcAs/fGaTnJeBFd7UoV22j3lzMLdM0Pw==", + "devOptional": true, + "requires": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + } + }, + "sass-graph": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-4.0.1.tgz", + "integrity": "sha512-5YCfmGBmxoIRYHnKK2AKzrAkCoQ8ozO+iumT8K4tXJXRVCPf+7s1/9KxTSW3Rbvf+7Y7b4FR3mWyLnQr3PHocA==", + "optional": true, + "peer": true, + "requires": { + "glob": "^7.0.0", + "lodash": "^4.17.11", + "scss-tokenizer": "^0.4.3", + "yargs": "^17.2.1" + } + }, + "sass-loader": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", + "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", + "requires": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "requires": { + "xmlchars": "^2.2.0" + } + }, + "scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "requires": {} + }, + "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==" + } + } + }, + "scss-tokenizer": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.4.3.tgz", + "integrity": "sha512-raKLgf1LI5QMQnG+RxHz6oK0sL3x3I4FN2UDLqgLOGO8hodECNnNh5BXn7fAyBxrA8zVzdQizQ6XjNJQ+uBwMw==", + "optional": true, + "peer": true, + "requires": { + "js-base64": "^2.4.9", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "optional": true, + "peer": true + } + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" + }, + "selfsigned": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "requires": { + "node-forge": "^1" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "requires": { + "lru-cache": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + } + } + }, + "serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + } + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "optional": true, + "peer": true + }, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + } + }, + "set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + } + }, + "set-getter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.1.tgz", + "integrity": "sha512-9sVWOy+gthr+0G9DzqqLaYNA7+5OKkSmcqjL9cBpDEaZrr3ShQlyX2cZ/O/ozE41oxn/Tt0LGEM/w4Rub3A3gw==", + "requires": { + "to-object-path": "^0.3.0" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==" + }, + "shiki": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.10.3.tgz", + "integrity": "sha512-eneCLncGuvPdTutJuLyUGS8QNPAVFO5Trvld2wgEq1e002mwctAhJKeMGWtWVXOIEzmlcLRqcgPSorR6AVzOmQ==", + "peer": true, + "requires": { + "@shikijs/core": "1.10.3", + "@types/hast": "^3.0.4" + } + }, + "side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "requires": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + } + }, + "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==" + }, + "sirv": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz", + "integrity": "sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==", + "dev": true, + "requires": { + "@polka/url": "^1.0.0-next.20", + "mrmime": "^1.0.0", + "totalist": "^3.0.0" + } + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + }, + "slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "dependencies": { + "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 + }, + "is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true + } + } + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "optional": true, + "peer": true + }, + "sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "requires": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "optional": true, + "peer": true, + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + }, + "source-map-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.2.tgz", + "integrity": "sha512-BokxPoLjyl3iOrgkWaakaxqnelAJSS+0V+De0kKIq6lyWrXuiPgYTGp6z3iHmqljKAaLXwZa+ctD8GccRJeVvg==", + "requires": { + "abab": "^2.0.5", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.1" + } + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + }, + "spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "optional": true, + "peer": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "optional": true, + "peer": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "optional": true, + "peer": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", + "optional": true, + "peer": true + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "sshpk": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "optional": true, + "peer": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" + }, + "stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" + } + } + }, + "stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" + }, + "stdout-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", + "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", + "optional": true, + "peer": true, + "requires": { + "readable-stream": "^2.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "optional": true, + "peer": true + }, + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "optional": true, + "peer": true, + "requires": { + "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" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "optional": true, + "peer": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "optional": true, + "peer": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true + }, + "string-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", + "integrity": "sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==", + "dev": true + }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "string-natural-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", + "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==" + }, + "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==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "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==" + } + } + }, + "string.prototype.matchall": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + } + }, + "string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + } + }, + "string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "requires": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "dependencies": { + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==" + } + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==" + }, + "strip-color": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/strip-color/-/strip-color-0.1.0.tgz", + "integrity": "sha512-p9LsUieSjWNNAxVCXLeilaDlmuUOrDS5/dF9znM1nZc7EGX5+zEFC0bEevsNIaldjlks+2jns5Siz6F9iK6jwA==" + }, + "strip-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", + "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==" + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" + }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "devOptional": true, + "requires": { + "min-indent": "^1.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" + }, + "style-loader": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.3.tgz", + "integrity": "sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw==", + "requires": {} + }, + "stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "requires": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + } + }, + "stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, + "sucrase": { + "version": "3.33.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.33.0.tgz", + "integrity": "sha512-ARGC7vbufOHfpvyGcZZXFaXCMZ9A4fffOGC5ucOW7+WHDGlAe8LJdf3Jts1sWhDeiI1RSWrKy5Hodl+JWGdW2A==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "7.1.6", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "dependencies": { + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==" + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, + "svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" + }, + "svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "requires": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + }, + "dependencies": { + "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==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "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==" + }, + "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==" + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "requires": { + "minimist": "^1.2.6" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==" + }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" + }, + "synckit": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "dev": true, + "requires": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + } + }, + "tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" + }, + "tailwindcss": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz", + "integrity": "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==", + "requires": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.18.2", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "dependencies": { + "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==", + "requires": { + "is-glob": "^4.0.3" + } + }, + "postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "requires": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + } + } + } + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" + }, + "tar": { + "version": "6.1.15", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", + "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", + "optional": true, + "peer": true, + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "optional": true, + "peer": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true, + "peer": true + } + } + }, + "temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==" + }, + "tempy": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", + "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", + "requires": { + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "dependencies": { + "type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==" + } + } + }, + "terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "requires": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + } + }, + "terser": { + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.0.tgz", + "integrity": "sha512-JpcpGOQLOXm2jsomozdMDpd5f8ZHh1rR48OFgWUH3QsyZcfPgv2qDCYbcDEAYNd4OZRj2bWYKpwdll/udZCk/Q==", + "requires": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + } + } + }, + "terser-webpack-plugin": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", + "requires": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + }, + "thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "requires": { + "any-promise": "^1.0.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "requires": { + "thenify": ">= 3.1.0 < 4" + } + }, + "throat": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz", + "integrity": "sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==" + }, + "throttle-debounce": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-2.3.0.tgz", + "integrity": "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==" + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "requires": { + "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" + } + }, + "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==" + }, + "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==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "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==" + }, + "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==" + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "tmp-promise": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", + "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", + "requires": { + "tmp": "^0.2.0" + }, + "dependencies": { + "tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==" + } + } + }, + "tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" + }, + "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==" + }, + "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==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "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==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "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 + }, + "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==", + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "toml": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/toml/-/toml-2.3.6.tgz", + "integrity": "sha512-gVweAectJU3ebq//Ferr2JUY4WKSDe5N+z0FvjDncLGyHmIDoxgY/2Ie4qfEIDm4IS7OA6Rmdm7pdEEdMcV/xQ==" + }, + "totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true + }, + "tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "dependencies": { + "universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==" + } + } + }, + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "requires": { + "punycode": "^2.1.1" + } + }, + "trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "optional": true, + "peer": true + }, + "true-case-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", + "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", + "optional": true, + "peer": true, + "requires": { + "glob": "^7.1.2" + } + }, + "tryer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", + "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==" + }, + "ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" + }, + "ts-invariant": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.10.3.tgz", + "integrity": "sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==", + "requires": { + "tslib": "^2.1.0" + } + }, + "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==", + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "requires": { + "minimist": "^1.2.0" + } + }, + "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==" + } + } + }, + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "tsx": { + "version": "4.16.2", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.16.2.tgz", + "integrity": "sha512-C1uWweJDgdtX2x600HjaFaucXTilT7tgUZHbOE4+ypskZ1OP8CRCSDkCxG6Vya9EwaFIVagWwpaVAn5wzypaqQ==", + "dev": true, + "requires": { + "esbuild": "~0.21.5", + "fsevents": "~2.3.3", + "get-tsconfig": "^4.7.5" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "optional": true, + "peer": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "optional": true, + "peer": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "requires": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + } + }, + "typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "requires": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + } + }, + "typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "requires": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + } + }, + "typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "requires": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typedoc": { + "version": "0.26.3", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.26.3.tgz", + "integrity": "sha512-6d2Sw9disvvpdk4K7VNjKr5/3hzijtfQVHRthhDqJgnhMHy1wQz4yPMJVKXElvnZhFr0nkzo+GzjXDTRV5yLpg==", + "peer": true, + "requires": { + "lunr": "^2.3.9", + "markdown-it": "^14.1.0", + "minimatch": "^9.0.5", + "shiki": "^1.9.1", + "yaml": "^2.4.5" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "peer": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "peer": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "yaml": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", + "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", + "peer": true + } + } + }, + "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==", + "requires": {} + }, + "typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==" + }, + "uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "peer": true + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "uncontrollable": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", + "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", + "requires": { + "@babel/runtime": "^7.6.3", + "@types/react": ">=16.9.11", + "invariant": "^2.2.4", + "react-lifecycles-compat": "^3.0.4" + } + }, + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "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==" + }, + "unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "requires": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + } + }, + "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==" + }, + "unicode-properties": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", + "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", + "requires": { + "base64-js": "^1.3.0", + "unicode-trie": "^2.0.0" + } + }, + "unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==" + }, + "unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "requires": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + }, + "dependencies": { + "pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==" + } + } + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + }, + "unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg==" + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" + }, + "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==", + "requires": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + } + }, + "update-notifier": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", + "dev": true, + "requires": { + "boxen": "^5.0.0", + "chalk": "^4.1.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^5.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.1.0", + "pupa": "^2.1.1", + "semver": "^7.3.4", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + } + }, + "use-memo-one": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz", + "integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==", + "requires": {} + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "util.promisify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", + "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" + } + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "requires": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "dependencies": { + "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==" + } + } + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "optional": true, + "peer": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "optional": true, + "peer": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "optional": true, + "peer": true + } + } + }, + "void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==" + }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "requires": { + "xml-name-validator": "^3.0.0" + } + }, + "walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "requires": { + "makeerror": "1.0.12" + } + }, + "warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "requires": { + "defaults": "^1.0.3" + } + }, + "web-vitals": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.2.tgz", + "integrity": "sha512-nYfoOqb4EmElljyXU2qdeE76KsvoHdftQKY4DzA9Aw8DervCg2bG634pHLrJ/d6+B4mE3nWTSJv8Mo7B2mbZkw==" + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==" + }, + "webpack": { + "version": "5.88.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.1.tgz", + "integrity": "sha512-FROX3TxQnC/ox4N+3xQoWZzvGXSuscxR32rbzjpXgEzWudJFEJBpdlkkob2ylrv5yzzufD1zph1OoFsLtm6stQ==", + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + } + }, + "webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "requires": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "dependencies": { + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + } + } + }, + "webpack-dev-server": { + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", + "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", + "requires": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.13.0" + }, + "dependencies": { + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + } + } + }, + "webpack-manifest-plugin": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-4.1.1.tgz", + "integrity": "sha512-YXUAwxtfKIJIKkhg03MKuiFAD72PlrqCiwdwO4VEXdRO5V0ORCNwaOwAZawPZalCbmH9kBDmXnNeQOw+BIEiow==", + "requires": { + "tapable": "^2.0.0", + "webpack-sources": "^2.2.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "webpack-sources": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.1.tgz", + "integrity": "sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==", + "requires": { + "source-list-map": "^2.0.1", + "source-map": "^0.6.1" + } + } + } + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==" + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==" + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "requires": { + "iconv-lite": "0.4.24" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, + "whatwg-fetch": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", + "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" + }, + "whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "requires": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "requires": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + } + }, + "which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "requires": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + } + }, + "which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "requires": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + } + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "optional": true, + "peer": true, + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "requires": { + "string-width": "^4.0.0" + } + }, + "workbox-background-sync": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-6.6.0.tgz", + "integrity": "sha512-jkf4ZdgOJxC9u2vztxLuPT/UjlH7m/nWRQ/MgGL0v8BJHoZdVGJd18Kck+a0e55wGXdqyHO+4IQTk0685g4MUw==", + "requires": { + "idb": "^7.0.1", + "workbox-core": "6.6.0" + } + }, + "workbox-broadcast-update": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-6.6.0.tgz", + "integrity": "sha512-nm+v6QmrIFaB/yokJmQ/93qIJ7n72NICxIwQwe5xsZiV2aI93MGGyEyzOzDPVz5THEr5rC3FJSsO3346cId64Q==", + "requires": { + "workbox-core": "6.6.0" + } + }, + "workbox-build": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-6.6.0.tgz", + "integrity": "sha512-Tjf+gBwOTuGyZwMz2Nk/B13Fuyeo0Q84W++bebbVsfr9iLkDSo6j6PST8tET9HYA58mlRXwlMGpyWO8ETJiXdQ==", + "requires": { + "@apideck/better-ajv-errors": "^0.3.1", + "@babel/core": "^7.11.1", + "@babel/preset-env": "^7.11.0", + "@babel/runtime": "^7.11.2", + "@rollup/plugin-babel": "^5.2.0", + "@rollup/plugin-node-resolve": "^11.2.1", + "@rollup/plugin-replace": "^2.4.1", + "@surma/rollup-plugin-off-main-thread": "^2.2.3", + "ajv": "^8.6.0", + "common-tags": "^1.8.0", + "fast-json-stable-stringify": "^2.1.0", + "fs-extra": "^9.0.1", + "glob": "^7.1.6", + "lodash": "^4.17.20", + "pretty-bytes": "^5.3.0", + "rollup": "^2.43.1", + "rollup-plugin-terser": "^7.0.0", + "source-map": "^0.8.0-beta.0", + "stringify-object": "^3.3.0", + "strip-comments": "^2.0.1", + "tempy": "^0.6.0", + "upath": "^1.2.0", + "workbox-background-sync": "6.6.0", + "workbox-broadcast-update": "6.6.0", + "workbox-cacheable-response": "6.6.0", + "workbox-core": "6.6.0", + "workbox-expiration": "6.6.0", + "workbox-google-analytics": "6.6.0", + "workbox-navigation-preload": "6.6.0", + "workbox-precaching": "6.6.0", + "workbox-range-requests": "6.6.0", + "workbox-recipes": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0", + "workbox-streams": "6.6.0", + "workbox-sw": "6.6.0", + "workbox-window": "6.6.0" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "requires": { + "whatwg-url": "^7.0.0" + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "requires": { + "punycode": "^2.1.0" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, + "whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + } + } + }, + "workbox-cacheable-response": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-6.6.0.tgz", + "integrity": "sha512-JfhJUSQDwsF1Xv3EV1vWzSsCOZn4mQ38bWEBR3LdvOxSPgB65gAM6cS2CX8rkkKHRgiLrN7Wxoyu+TuH67kHrw==", + "requires": { + "workbox-core": "6.6.0" + } + }, + "workbox-core": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.6.0.tgz", + "integrity": "sha512-GDtFRF7Yg3DD859PMbPAYPeJyg5gJYXuBQAC+wyrWuuXgpfoOrIQIvFRZnQ7+czTIQjIr1DhLEGFzZanAT/3bQ==" + }, + "workbox-expiration": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-6.6.0.tgz", + "integrity": "sha512-baplYXcDHbe8vAo7GYvyAmlS4f6998Jff513L4XvlzAOxcl8F620O91guoJ5EOf5qeXG4cGdNZHkkVAPouFCpw==", + "requires": { + "idb": "^7.0.1", + "workbox-core": "6.6.0" + } + }, + "workbox-google-analytics": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-6.6.0.tgz", + "integrity": "sha512-p4DJa6OldXWd6M9zRl0H6vB9lkrmqYFkRQ2xEiNdBFp9U0LhsGO7hsBscVEyH9H2/3eZZt8c97NB2FD9U2NJ+Q==", + "requires": { + "workbox-background-sync": "6.6.0", + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" + } + }, + "workbox-navigation-preload": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-6.6.0.tgz", + "integrity": "sha512-utNEWG+uOfXdaZmvhshrh7KzhDu/1iMHyQOV6Aqup8Mm78D286ugu5k9MFD9SzBT5TcwgwSORVvInaXWbvKz9Q==", + "requires": { + "workbox-core": "6.6.0" + } + }, + "workbox-precaching": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-6.6.0.tgz", + "integrity": "sha512-eYu/7MqtRZN1IDttl/UQcSZFkHP7dnvr/X3Vn6Iw6OsPMruQHiVjjomDFCNtd8k2RdjLs0xiz9nq+t3YVBcWPw==", + "requires": { + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" + } + }, + "workbox-range-requests": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-6.6.0.tgz", + "integrity": "sha512-V3aICz5fLGq5DpSYEU8LxeXvsT//mRWzKrfBOIxzIdQnV/Wj7R+LyJVTczi4CQ4NwKhAaBVaSujI1cEjXW+hTw==", + "requires": { + "workbox-core": "6.6.0" + } + }, + "workbox-recipes": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-6.6.0.tgz", + "integrity": "sha512-TFi3kTgYw73t5tg73yPVqQC8QQjxJSeqjXRO4ouE/CeypmP2O/xqmB/ZFBBQazLTPxILUQ0b8aeh0IuxVn9a6A==", + "requires": { + "workbox-cacheable-response": "6.6.0", + "workbox-core": "6.6.0", + "workbox-expiration": "6.6.0", + "workbox-precaching": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" + } + }, + "workbox-routing": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.6.0.tgz", + "integrity": "sha512-x8gdN7VDBiLC03izAZRfU+WKUXJnbqt6PG9Uh0XuPRzJPpZGLKce/FkOX95dWHRpOHWLEq8RXzjW0O+POSkKvw==", + "requires": { + "workbox-core": "6.6.0" + } + }, + "workbox-strategies": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.6.0.tgz", + "integrity": "sha512-eC07XGuINAKUWDnZeIPdRdVja4JQtTuc35TZ8SwMb1ztjp7Ddq2CJ4yqLvWzFWGlYI7CG/YGqaETntTxBGdKgQ==", + "requires": { + "workbox-core": "6.6.0" + } + }, + "workbox-streams": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-6.6.0.tgz", + "integrity": "sha512-rfMJLVvwuED09CnH1RnIep7L9+mj4ufkTyDPVaXPKlhi9+0czCu+SJggWCIFbPpJaAZmp2iyVGLqS3RUmY3fxg==", + "requires": { + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0" + } + }, + "workbox-sw": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-6.6.0.tgz", + "integrity": "sha512-R2IkwDokbtHUE4Kus8pKO5+VkPHD2oqTgl+XJwh4zbF1HyjAbgNmK/FneZHVU7p03XUt9ICfuGDYISWG9qV/CQ==" + }, + "workbox-webpack-plugin": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-6.6.0.tgz", + "integrity": "sha512-xNZIZHalboZU66Wa7x1YkjIqEy1gTR+zPM+kjrYJzqN7iurYZBctBLISyScjhkJKYuRrZUP0iqViZTh8rS0+3A==", + "requires": { + "fast-json-stable-stringify": "^2.1.0", + "pretty-bytes": "^5.4.1", + "upath": "^1.2.0", + "webpack-sources": "^1.4.3", + "workbox-build": "6.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + } + } + }, + "workbox-window": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-6.6.0.tgz", + "integrity": "sha512-L4N9+vka17d16geaJXXRjENLFldvkWy7JyGxElRD0JvBxvFEd8LOhr+uXCcar/NzAmIBRv9EZ+M+Qr4mOoBITw==", + "requires": { + "@types/trusted-types": "^2.0.2", + "workbox-core": "6.6.0" + } + }, + "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==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "requires": {} + }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + }, + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "dependencies": { + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" + } + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + }, + "zen-observable": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz", + "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==" + }, + "zen-observable-ts": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.2.5.tgz", + "integrity": "sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg==", + "requires": { + "zen-observable": "0.8.15" + } + }, + "zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==" + } + } +} diff --git a/package.json b/package.json index 6526d77a59..799c4758da 100644 --- a/package.json +++ b/package.json @@ -1,34 +1,80 @@ { - "name": "my-app", - "version": "0.1.0", + "name": "talawa-admin", + "version": "3.0.0", "private": true, + "type": "module", + "config-overrides-path": "scripts/config-overrides", "dependencies": { - "@testing-library/jest-dom": "^5.11.4", - "@testing-library/react": "^11.1.0", - "@testing-library/user-event": "^12.1.10", - "@types/jest": "^26.0.15", - "@types/node": "^12.0.0", - "@types/react": "^17.0.0", - "@types/react-dom": "^17.0.0", - "eslint-config-prettier": "^8.3.0", - "eslint-plugin-prettier": "^3.4.0", - "prettier": "^2.3.0", + "@apollo/client": "^3.4.0-beta.19", + "@apollo/link-error": "^2.0.0-beta.3", + "@apollo/react-testing": "^4.0.0", + "@dicebear/collection": "^8.0.1", + "@dicebear/core": "^8.0.1", + "@emotion/react": "^11.11.4", + "@emotion/styled": "^11.11.5", + "@mui/icons-material": "^5.16.1", + "@mui/material": "^5.16.4", + "@mui/private-theming": "^5.15.12", + "@mui/system": "^5.14.12", + "@mui/x-charts": "^7.8.0", + "@mui/x-data-grid": "^7.11.0", + "@mui/x-date-pickers": "^7.6.1", + "@pdfme/generator": "^1.2.6", + "bootstrap": "^5.3.3", + "customize-cra": "^1.0.0", + "dayjs": "^1.11.11", + "flag-icons": "^6.6.6", + "graphql": "^16.9.0", + "graphql-tag": "^2.12.6", + "graphql-ws": "^5.16.0", + "history": "^5.3.0", + "i18next": "^21.8.14", + "i18next-browser-languagedetector": "^8.0.0", + "i18next-http-backend": "^2.5.2", + "inquirer": "^8.0.0", + "jest-watch-typeahead": "^2.2.2", + "js-cookie": "^3.0.1", + "markdown-toc": "^1.2.0", + "prettier": "^3.3.2", "react": "^17.0.2", - "react-bootstrap": "^1.5.2", + "react-app-rewired": "^2.2.1", + "react-beautiful-dnd": "^13.1.1", + "react-bootstrap": "^2.7.4", + "react-datepicker": "^7.3.0", "react-dom": "^17.0.2", - "react-router-dom": "^5.2.0", - "react-scripts": "4.0.3", - "typescript": "^4.2.4", - "web-vitals": "^1.0.1" + "react-google-recaptcha": "^3.1.0", + "react-i18next": "^11.18.1", + "react-icons": "^5.2.1", + "react-infinite-scroll-component": "^6.1.0", + "react-multi-carousel": "^2.8.5", + "react-redux": "^7.2.5", + "react-router-dom": "^6.25.1", + "react-scripts": "5.0.1", + "react-toastify": "^9.0.3", + "react-tooltip": "^5.27.1", + "redux": "^4.1.1", + "redux-thunk": "^2.3.0", + "sanitize-html": "^2.13.0", + "typedoc-plugin-markdown": "^4.2.1", + "typescript": "^4.3.5", + "web-vitals": "^4.2.2" }, "scripts": { - "serve": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test", + "serve": "cross-env ESLINT_NO_DEV_ERRORS=true node ./scripts/config-overrides/custom_start.js", + "build": "node ./scripts/config-overrides/custom_build.js", + "test": "cross-env NODE_ENV=test node scripts/test.js --env=./scripts/custom-test-env.js --watchAll --coverage", "eject": "react-scripts eject", - "lint": "eslint 'src/*.{ts,tsx}'", - "lint-fix": "eslint 'src/*.{ts,tsx}' --fix", - "format": "prettier --write \"**/*.{ts,tsx,json,scss,css}\"" + "lint:check": "eslint \"**/*.{ts,tsx}\" --max-warnings=0", + "lint:fix": "eslint --fix \"**/*.{ts,tsx}\"", + "format:fix": "prettier --write \"**/*.{ts,tsx,json,scss,css}\"", + "format:check": "prettier --check \"**/*.{ts,tsx,json,scss,css}\"", + "typecheck": "tsc --project tsconfig.json --noEmit", + "prepare": "husky install", + "jest-preview": "jest-preview", + "update:toc": "node scripts/githooks/update-toc.js", + "lint-staged": "lint-staged --concurrent false", + "setup": "tsx setup.ts", + "check-localstorage": "node scripts/githooks/check-localstorage-usage.js" }, "eslintConfig": { "extends": [ @@ -49,8 +95,56 @@ ] }, "devDependencies": { - "@typescript-eslint/eslint-plugin": "^4.24.0", - "@typescript-eslint/parser": "^4.24.0", - "eslint-plugin-react-hooks": "^4.2.0" + "@babel/plugin-proposal-private-property-in-object": "^7.21.11", + "@testing-library/jest-dom": "^6.4.5", + "@testing-library/react": "^11.1.0", + "@testing-library/user-event": "^12.1.10", + "@types/inquirer": "^9.0.7", + "@types/jest": "^29.5.12", + "@types/js-cookie": "^3.0.6", + "@types/node": "^20.12.12", + "@types/node-fetch": "^2.6.10", + "@types/react": "^17.0.14", + "@types/react-beautiful-dnd": "^13.1.8", + "@types/react-bootstrap": "^0.32.32", + "@types/react-datepicker": "^4.1.4", + "@types/react-dom": "^17.0.9", + "@types/react-google-recaptcha": "^2.1.5", + "@types/react-router-dom": "^5.1.8", + "@types/sanitize-html": "^2.11.0", + "@typescript-eslint/eslint-plugin": "^5.9.0", + "@typescript-eslint/parser": "^5.9.0", + "cross-env": "^7.0.3", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-jest": "^25.3.4", + "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-react": "^7.34.1", + "eslint-plugin-tsdoc": "^0.2.17", + "husky": "^8.0.3", + "identity-obj-proxy": "^3.0.0", + "jest": "^29.7.0", + "jest-localstorage-mock": "^2.4.19", + "jest-location-mock": "^2.0.0", + "jest-preview": "^0.3.1", + "lint-staged": "^15.2.7", + "postcss-modules": "^6.0.0", + "sass": "^1.77.4", + "tsx": "^4.16.2" + }, + "resolutions": { + "@apollo/client": "^3.4.0-beta.19", + "@types/react": "17.0.2", + "@types/react-dom": "17.0.2", + "graphql": "^16.5.0" + }, + "engines": { + "node": ">=20.x" + }, + "lint-staged": { + "**/*.{ts, tsx, json, scss, css}": [ + "prettier --write" + ], + "**/*.{ts, tsx, json}": "eslint --fix" } } diff --git a/public/favicon.ico b/public/favicon.ico index a11777cc47..0675af2934 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/favicon_palisadoes.ico b/public/favicon_palisadoes.ico new file mode 100644 index 0000000000..0675af2934 Binary files /dev/null and b/public/favicon_palisadoes.ico differ diff --git a/public/images/REACT_SITE_KEY.webp b/public/images/REACT_SITE_KEY.webp new file mode 100644 index 0000000000..9afe77c4d5 Binary files /dev/null and b/public/images/REACT_SITE_KEY.webp differ diff --git a/public/images/jest-preview.webp b/public/images/jest-preview.webp new file mode 100644 index 0000000000..a5810192af Binary files /dev/null and b/public/images/jest-preview.webp differ diff --git a/public/logo512.png b/public/images/logo512.png similarity index 100% rename from public/logo512.png rename to public/images/logo512.png diff --git a/public/images/svg/angleDown.svg b/public/images/svg/angleDown.svg new file mode 100644 index 0000000000..0dfea5e56c --- /dev/null +++ b/public/images/svg/angleDown.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/svg/profiledefault.svg b/public/images/svg/profiledefault.svg new file mode 100644 index 0000000000..a321caaeab --- /dev/null +++ b/public/images/svg/profiledefault.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/index.html b/public/index.html index 72527d8e95..3bd6e258e7 100644 --- a/public/index.html +++ b/public/index.html @@ -2,11 +2,23 @@ - + - + + + + + + Talawa Admin diff --git a/public/locales/en/common.json b/public/locales/en/common.json new file mode 100644 index 0000000000..d3f108c550 --- /dev/null +++ b/public/locales/en/common.json @@ -0,0 +1,86 @@ +{ + "firstName": "First Name", + "lastName": "Last Name", + "searchByName": "Search By Name", + "loading": "Loading...", + "endOfResults": "End of results", + "noResultsFoundFor": "No results found for ", + "edit": "Edit", + "admins": "Admins", + "admin": "ADMIN", + "user": "USER", + "superAdmin": "SUPERADMIN", + "members": "Members", + "logout": "Logout", + "login": "Login", + "register": "Register", + "menu": "Menu", + "settings": "Settings", + "users": "Users", + "requests": "Requests", + "OR": "OR", + "cancel": "Cancel", + "close": "Close", + "create": "Create", + "delete": "Delete", + "done": "Done", + "yes": "Yes", + "no": "No", + "filter": "Filter", + "search": "Search", + "description": "Description", + "saveChanges": "Save Changes", + "resetChanges": "Reset Changes", + "displayImage": "Display Image", + "enterEmail": "Enter Email", + "emailAddress": "Email Address", + "email": "Email", + "name": "Name", + "desc": "Description", + "enterPassword": "Enter Password", + "password": "Password", + "confirmPassword": "Confirm Password", + "forgotPassword": "Forgot Password ?", + "talawaAdminPortal": "Talawa Admin Portal", + "address": "Address", + "location": "Location", + "enterLocation": "Enter Location", + "joined": "Joined", + "startDate": "Start Date", + "endDate": "End Date", + "startTime": "Start Time", + "endTime": "End Time", + "My Organizations": "My Organizations", + "Dashboard": "Dashboard", + "People": "People", + "Events": "Events", + "Venues": "Venues", + "Action Items": "Action Items", + "Posts": "Posts", + "Block/Unblock": "Block/Unblock", + "Advertisement": "Advertisement", + "Funds": "Funds", + "Membership Requests": "Membership Requests", + "Plugins": "Plugins", + "Plugin Store": "Plugin Store", + "Settings": "Settings", + "createdOn": "Created On", + "createdBy": "Created By", + "usersRole": "User's Role", + "changeRole": "Change Role", + "action": "Action", + "removeUser": "Remove User", + "remove": "Remove", + "viewProfile": "View Profile", + "profile": "Profile", + "noFiltersApplied": "No filters applied", + "manage": "Manage", + "searchResultsFor": "Search results for {{text}}", + "none": "None", + "sort": "Sort", + "Donate": "Donate", + "addedSuccessfully": "{{item}} added Successfully", + "updatedSuccessfully": "{{item}} updated Successfully", + "removedSuccessfully": "{{item}} removed Successfully", + "successfullyUpdated": "Successfully Updated" +} diff --git a/public/locales/en/errors.json b/public/locales/en/errors.json new file mode 100644 index 0000000000..155d747bcf --- /dev/null +++ b/public/locales/en/errors.json @@ -0,0 +1,10 @@ +{ + "talawaApiUnavailable": "Talawa-API service is unavailable!. Is it running? Check your network connectivity too.", + "notFound": "Not found", + "unknownError": "An unknown error occurred. Please try again later. {{msg}}", + "notAuthorised": "Sorry! you are not Authorised!", + "errorSendingMail": "Error sending mail", + "emailNotRegistered": "Email not registered", + "notFoundMsg": "Oops! The Page you requested was not found!", + "errorOccurredCouldntCreate": "An error occurred. Couldn't create {{entity}}" +} diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json new file mode 100644 index 0000000000..33cdd02286 --- /dev/null +++ b/public/locales/en/translation.json @@ -0,0 +1,983 @@ +{ + "loginPage": { + "title": "Talawa Admin", + "fromPalisadoes": "An open source application by Palisadoes Foundation volunteers", + "userLogin": "User Login", + "atleast_8_char_long": "Atleast 8 Character long", + "atleast_6_char_long": "Atleast 6 Character long", + "firstName_invalid": "First name should contain only lower and upper case letters", + "lastName_invalid": "Last name should contain only lower and upper case letters", + "password_invalid": "Password should contain atleast one lowercase letter, one uppercase letter, one numeric value and one special character", + "email_invalid": "Email should have atleast 8 characters", + "Password_and_Confirm_password_mismatches.": "Password and Confirm password mismatches.", + "doNotOwnAnAccount": "Do not own an account?", + "captchaError": "Captcha Error!", + "Please_check_the_captcha": "Please, check the captcha.", + "Something_went_wrong": "Something went wrong, Please try after sometime.", + "passwordMismatches": "Password and Confirm password mismatches.", + "fillCorrectly": "Fill all the Details Correctly.", + "successfullyRegistered": "Successfully Registered. Please wait until you will be approved.", + "lowercase_check": "Atleast one lowercase letter", + "uppercase_check": "Atleast one uppercase letter", + "numeric_value_check": "Atleaset one numeric value", + "special_char_check": "Atleast one special character", + "selectOrg": "Select an organization", + "afterRegister": "Successfully registered. Please wait for admin to approve your request." + }, + "userLoginPage": { + "title": "Talawa Admin", + "fromPalisadoes": "An open source application by Palisadoes Foundation volunteers", + "atleast_8_char_long": "Atleast 8 Character long", + "Password_and_Confirm_password_mismatches.": "Password and Confirm password mismatches.", + "doNotOwnAnAccount": "Do not own an account?", + "captchaError": "Captcha Error!", + "Please_check_the_captcha": "Please, check the captcha.", + "Something_went_wrong": "Something went wrong, Please try after sometime.", + "passwordMismatches": "Password and Confirm password mismatches.", + "fillCorrectly": "Fill all the Details Correctly.", + "successfullyRegistered": "Successfully Registered. Please wait until you will be approved.", + "userLogin": "User Login", + "afterRegister": "Successfully registered. Please wait for admin to approve your request.", + "selectOrg": "Select an organization" + }, + "latestEvents": { + "eventCardTitle": "Upcoming Events", + "eventCardSeeAll": "See All", + "noEvents": "No Upcoming Events" + }, + "latestPosts": { + "latestPostsTitle": "Latest Posts", + "seeAllLink": "See All", + "noPostsCreated": "No Posts Created" + }, + "listNavbar": { + "roles": "Roles" + }, + "leftDrawer": { + "my organizations": "My Organizations", + "requests": "Membership Requests", + "communityProfile": "Community Profile" + }, + "leftDrawerOrg": { + "Dashboard": "Dashboard", + "People": "People", + "Events": "Events", + "Contributions": "Contributions", + "Posts": "Posts", + "Block/Unblock": "Block/Unblock", + "Plugins": "Plugins", + "Plugin Store": "Plugin Store", + "Advertisement": "Advertisements", + "allOrganizations": "All Organizations", + "yourOrganization": "Your Organization", + "notification": "Notification", + "language": "Language", + "notifications": "Notifications", + "spamsThe": "spams the", + "group": "group", + "noNotifications": "No Notifications" + }, + "orgList": { + "title": "Talawa Organizations", + "you": "You", + "designation": "Designation", + "my organizations": "My Organizations", + "createOrganization": "Create Organization", + "createSampleOrganization": "Create Sample Organization", + "city": "City", + "countryCode": "Country Code", + "dependentLocality": "Dependent Locality", + "line1": "Line 1", + "line2": "Line 2", + "postalCode": "Postal Code", + "sortingCode": "Sorting code", + "state": "State / Province", + "userRegistrationRequired": "User Registration Required", + "visibleInSearch": "Visible In Search", + "enterName": "Enter Name", + "sort": "Sort", + "Latest": "Latest", + "Earliest": "Earliest", + "noOrgErrorTitle": "Organizations Not Found", + "sampleOrgDuplicate": "Only one sample organization allowed", + "noOrgErrorDescription": "Please create an organization through dashboard", + "manageFeatures": "Manage Features", + "manageFeaturesInfo": "Creation Successful ! Please select features that you want to enale for this organization from the plugin store.", + "goToStore": "Go to Plugin Store", + "enableEverything": "Enable Everything", + "sampleOrgSuccess": "Sample Organization Successfully Created" + }, + "orgListCard": { + "manage": "Manage", + "sampleOrganization": "Sample Organization" + }, + "paginationList": { + "rowsPerPage": "rows per page", + "all": "All" + }, + "requests": { + "title": "Membership Requests", + "sl_no": "Sl. No.", + "accept": "Accept", + "reject": "Reject", + "searchRequests": "Search membership requests", + "noOrgError": "Organizations not found, please create an organization through dashboard", + "noRequestsFound": "No Membership Requests Found", + "acceptedSuccessfully": "Request accepted successfully", + "rejectedSuccessfully": "Request rejected successfully", + "noOrgErrorTitle": "Organizations Not Found", + "noOrgErrorDescription": "Please create an organization through dashboard" + }, + "users": { + "title": "Talawa Roles", + "joined_organizations": "Joined Organizations", + "blocked_organizations": "Blocked Organizations", + "orgJoinedBy": "Organizations Joined By", + "orgThatBlocked": "Organizations That Blocked", + "hasNotJoinedAnyOrg": "has not joined any organization", + "isNotBlockedByAnyOrg": "is not blocked by any organization", + "searchByOrgName": "Search By Organization Name", + "view": "View", + "enterName": "Enter Name", + "loadingUsers": "Loading Users...", + "noUserFound": "No User Found", + "sort": "Sort", + "Newest": "Newest First", + "Oldest": "Oldest First", + "noOrgError": "Organizations not found, please create an organization through dashboard", + "roleUpdated": "Role Updated.", + "joinNow": "Join Now", + "visit": "Visit", + "withdraw": "Widthdraw", + "removeUserFrom": "Remove User from {{org}}", + "removeConfirmation": "Are you sure you want to remove '{{name}}' from organization '{{org}}'?" + }, + "communityProfile": { + "title": "Community Profile", + "editProfile": "Edit Profile", + "communityProfileInfo": "These details will appear on the login/signup screen for you and your community members", + "communityName": "Community Name", + "wesiteLink": "Website Link", + "logo": "Logo", + "social": "Social Media Links", + "url": "Enter url", + "profileChangedMsg": "Successfully updated the Profile Details.", + "resetData": "Successfully reset the Profile Details." + }, + "dashboard": { + "title": "Dashboard", + "about": "About", + "deleteThisOrganization": "Delete This Organization", + "statistics": "Statistics", + "posts": "Posts", + "events": "Events", + "blockedUsers": "Blocked Users", + "viewAll": "View All", + "upcomingEvents": "Upcoming Events", + "noUpcomingEvents": "No Upcoming Events", + "latestPosts": "Latest Posts", + "noPostsPresent": "No Posts Present", + "membershipRequests": "Membership requests", + "noMembershipRequests": "No Membership requests present" + }, + "organizationPeople": { + "title": "Talawa Members", + "filterByName": "Filter by Name", + "filterByLocation": "Filter by Location", + "filterByEvent": "Filter by Event", + "searchName": "Enter Name", + "searchevent": "Enter Event", + "searchFullName": "Enter Full Name", + "people": "People", + "sort": "Search by Role", + "actions": "Actions", + "addMembers": "Add Members", + "existingUser": "Existing User", + "newUser": "New User", + "enterFirstName": "Enter your first name", + "enterLastName": "Enter your last name", + "enterConfirmPassword": "Enter Password to confirm", + "organization": "Organization", + "invalidDetailsMessage": "Please enter valid details." + }, + "userListCard": { + "addAdmin": "Add Admin", + "addedAsAdmin": "User is added as admin." + }, + "orgAdminListCard": { + "remove": "Remove", + "removeAdmin": "Remove Admin", + "removeAdminMsg": "Do you want to remove this admin?", + "adminRemoved": "The admin is removed." + }, + "orgPeopleListCard": { + "remove": "Remove", + "removeMember": "Remove Member", + "removeMemberMsg": "Do you want to remove this member?", + "memberRemoved": "The Member is removed" + }, + "organizationEvents": { + "title": "Events", + "filterByTitle": "Filter by Title", + "filterByLocation": "Filter by Location", + "filterByDescription": "Filter by Description", + "addEvent": "Add Event", + "eventDetails": "Event Details", + "eventTitle": "Title", + "allDay": "All Day", + "recurringEvent": "Recurring Event", + "isPublic": "Is Public", + "isRegistrable": "Is Registrable", + "createEvent": "Create Event", + "enterFilter": "Enter Filter", + "enterTitle": "Enter Title", + "enterDescrip": "Enter Description", + "searchEventName": "Search Event Name", + "eventType": "Event Type", + "eventCreated": "Congratulations! The Event is created.", + "customRecurrence": "Custom Recurrence", + "repeatsEvery": "Repeats Every", + "repeatsOn": "Repeats On", + "ends": "Ends", + "never": "Never", + "on": "On", + "after": "After", + "occurences": "occurences" + }, + "organizationActionItems": { + "actionItemCategory": "Action Item Category", + "actionItemDetails": "Action Item Details", + "actionItemCompleted": "Action Item Completed", + "assignee": "Assignee", + "assigner": "Assigner", + "assignmentDate": "Assignment Date", + "active": "Active", + "clearFilters": "Clear Filters", + "completed": "Completed", + "completionDate": "Completion Date", + "createActionItem": "Create Action Items", + "deleteActionItem": "Delete Action Item", + "deleteActionItemMsg": "Do you want to remove this action item?", + "details": "Details", + "dueDate": "Due Date", + "earliest": "Earliest", + "editActionItem": "Edit Action Item", + "isCompleted": "Completed", + "latest": "Latest", + "makeActive": "Active", + "noActionItems": "No Action Items", + "options": "Options", + "preCompletionNotes": "Notes", + "actionItemActive": "Active", + "markCompletion": "Mark Completion", + "actionItemStatus": "Action Item Status", + "postCompletionNotes": "Completion Notes", + "selectActionItemCategory": "Select an action item category", + "selectAssignee": "Select an assignee", + "status": "Status", + "successfulCreation": "Action Item created successfully", + "successfulUpdation": "Action Item updated successfully", + "successfulDeletion": "Action Item deleted successfully", + "title": "Action Items" + }, + "organizationAgendaCategory": { + "agendaCategoryDetails": "Agenda Category Details", + "updateAgendaCategory": "Update Agenda Category", + "title": "Agenda Categories", + "name": "Category", + "description": "Description", + "createdBy": "Created By", + "options": "Options", + "createAgendaCategory": "Create Agenda Category", + "noAgendaCategories": "No Agenda Categories", + "update": "Update", + "agendaCategoryCreated": "Agenda Category created successfully", + "agendaCategoryUpdated": "Agenda Category updated successfully", + "agendaCategoryDeleted": "Agenda Category deleted successfully", + "deleteAgendaCategory": "Delete Agenda Category", + "deleteAgendaCategoryMsg": "Do you want to remove this agenda category?" + }, + "agendaItems": { + "agendaItemDetails": "Agenda Item Details", + "updateAgendaItem": "Update Agenda Item", + "title": "Title", + "enterTitle": "Enter Title", + "sequence": "Sequence", + "description": "Description", + "enterDescription": "Enter Description", + "category": "Agenda Category", + "attachments": "Attachments", + "attachmentLimit": "Add any image file or video file upto 10MB", + "fileSizeExceedsLimit": "File size exceeds the limit which is 10MB", + "urls": "URLs", + "url": "add link to URL", + "enterUrl": "https://example.com", + "invalidUrl": "Please enter a valid URL", + "link": "Link", + "createdBy": "Created By", + "regular": "Regular", + "note": "Note", + "duration": "Duration", + "enterDuration": "mm:ss", + "options": "Options", + "createAgendaItem": "Create Agenda Item", + "noAgendaItems": "No Agenda Items", + "selectAgendaItemCategory": "Select an agenda item category", + "update": "Update", + "delete": "Delete", + "agendaItemCreated": "Agenda Item created successfully", + "agendaItemUpdated": "Agenda Item updated successfully", + "agendaItemDeleted": "Agenda Item deleted successfully", + "deleteAgendaItem": "Delete Agenda Item", + "deleteAgendaItemMsg": "Do you want to remove this agenda item?" + }, + "eventListCard": { + "deleteEvent": "Delete Event", + "deleteEventMsg": "Do you want to remove this event?", + "editEvent": "Edit Event", + "eventTitle": "Title", + "alreadyRegistered": "Already registered", + "allDay": "All Day", + "recurringEvent": "Recurring Event", + "isPublic": "Is Public", + "isRegistrable": "Is Registrable", + "updatePost": "Update Post", + "eventDetails": "Event Details", + "eventDeleted": "Event deleted successfully.", + "eventUpdated": "Event updated successfully.", + "thisInstance": "This Instance", + "thisAndFollowingInstances": "This & Following Instances", + "allInstances": "All Instances", + "customRecurrence": "Custom Recurrence", + "repeatsEvery": "Repeats Every", + "repeatsOn": "Repeats On", + "ends": "Ends", + "never": "Never", + "on": "On", + "after": "After", + "occurences": "occurences" + }, + "funds": { + "title": "Funds", + "createFund": "Create Fund", + "fundName": "Fund Name", + "fundId": "Fund (Reference) ID", + "taxDeductible": "Tax Deductible", + "default": "Default", + "archived": "Archived", + "fundCreate": "Create Fund", + "fundUpdate": "Update Fund", + "fundDelete": "Delete Fund", + "noFundsFound": "No Funds Found", + "createdBy": "Created By", + "createdOn": "Created On", + "status": "Status", + "fundCreated": "Fund created successfully", + "fundUpdated": "Fund updated successfully", + "fundDeleted": "Fund deleted successfully", + "deleteFundMsg": "Are you sure you want to delete this fund?", + "createdLatest": "Created Latest", + "createdEarliest": "Created Earliest", + "viewCampaigns": "View Campaigns" + }, + "fundCampaign": { + "title": "Fundraising Campaigns", + "campaignName": "Campaign Name", + "campaignOptions": "Options", + "fundingGoal": "Funding Goal", + "addCampaign": "Add Campaign", + "createdCampaign": "Campaign created successfully", + "updatedCampaign": "Campaign updated successfully", + "deletedCampaign": "Campaign deleted successfully", + "deleteCampaignMsg": "Are you sure you want to delete this campaign?", + "noCampaigns": "No Campaigns Found", + "createCampaign": "Create Campaign", + "updateCampaign": "Update Campaign", + "deleteCampaign": "Delete Campaign", + "currency": "Currency", + "selectCurrency": "Select Currency", + "searchFullName": "Search By Name", + "viewPledges": "View Pledges", + "noCampaignsFound": "No Campaigns Found", + "latestEndDate": "Latest End Date", + "earliestEndDate": "Earliest End Date", + "lowestGoal": "Lowest Goal", + "highestGoal": "Highest Goal" + }, + "pledges": { + "title": "Fund Campaign Pledges", + "pledgeAmount": "Pledge Amount", + "pledgeOptions": "Options", + "pledgeCreated": "Pledge created successfully", + "pledgeUpdated": "Pledge updated successfully", + "pledgeDeleted": "Pledge deleted successfully", + "addPledge": "Add Pledge", + "createPledge": "Create Pledge", + "currency": "Currency", + "selectCurrency": "Select Currency", + "updatePledge": "Update Pledge", + "deletePledge": "Delete Pledge", + "amount": "Amount", + "editPledge": "Edit Pledge", + "deletePledgeMsg": "Are you sure you want to delete this pledge?", + "noPledges": "No Pledges Found", + "searchPledger": "Search By Pledgers", + "highestAmount": "Highest Amount", + "lowestAmount": "Lowest Amount", + "latestEndDate": "Latest End Date", + "earliestEndDate": "Earliest End Date", + "campaigns": "Campaigns", + "pledges": "Pledges", + "endsOn": "Ends on", + "raisedAmount": "Raised amount ", + "pledgedAmount": "Pledged amount" + }, + "orgPost": { + "title": "Posts", + "searchPost": "Search Post", + "posts": "Posts", + "createPost": "Create Post", + "postDetails": "Post Details", + "postTitle1": "Write title of the post", + "postTitle": "Title", + "addMedia": "Upload Media", + "information": "Information", + "information1": "Write information of the post", + "addPost": "Add Post", + "searchTitle": "Search By Title", + "searchText": "Search By Text", + "ptitle": "Post Title", + "postDes": "What do you to talk about?", + "Title": "Title", + "Text": "Text", + "searchBy": "Search By", + "Oldest": "Oldest First", + "Latest": "Latest First", + "sortPost": "Sort Post", + "tag": " Your browser does not support the video tag", + "postCreatedSuccess": "Congratulations! You have Posted Something.", + "pinPost": "Pin post", + "Next": "Next Page", + "Previous": "Previous Page" + }, + "postNotFound": { + "post": "Post", + "not found!": "Not Found!", + "organization": "Organization", + "post not found!": "Post Not Found!", + "organization not found!": "Organization Not Found!" + }, + "userNotFound": { + "not found!": "Not Found!", + "roles": "Roles", + "user not found!": "User Not Found!", + "member not found!": "Member Not Found!", + "admin not found!": "Admin Not Found!", + "roles not found!": "Roles Not Found!" + }, + "orgPostCard": { + "author": "Author", + "imageURL": "Image URL", + "videoURL": "Video URL", + "deletePost": "Delete Post", + "deletePostMsg": "Do you want to remove this post?", + "editPost": "Edit Post", + "postTitle": "Title", + "postTitle1": "Edit title of the post", + "information1": "Edit information of the post", + "information": "Information", + "image": "Image", + "video": "Video", + "updatePost": "Update Post", + "postDeleted": "Post deleted successfully.", + "postUpdated": "Post Updated successfully.", + "tag": " Your browser does not support the video tag", + "pin": "Pin Post" + }, + "blockUnblockUser": { + "title": "Block/Unblock User", + "pageName": "Block/Unblock", + "listOfUsers": "List of Users who spammed", + "block_unblock": "Block/Unblock", + "unblock": "UnBlock", + "block": "Block", + "orgName": "Enter Name", + "blockedSuccessfully": "User blocked successfully", + "Un-BlockedSuccessfully": "User Un-Blocked successfully", + "allMembers": "All Members", + "blockedUsers": "Blocked Users", + "searchByFirstName": "Search By First Name", + "searchByLastName": "Search By Last Name", + "noSpammerFound": "No spammer found" + }, + "eventManagement": { + "title": "Event Management", + "dashboard": "Dashboard", + "registrants": "Registrants", + "eventActions": "Event Actions", + "eventAgendas": "Event Agendas", + "eventStats": "Event Statistics", + "to": "TO" + }, + "forgotPassword": { + "title": "Talawa Forgot Password", + "registeredEmail": "Registered Email", + "getOtp": "Get OTP", + "enterOtp": "Enter OTP", + "enterNewPassword": "Enter New Password", + "cofirmNewPassword": "Confirm New Password", + "changePassword": "Change Password", + "backToLogin": "Back to Login", + "userOtp": "e.g. 12345", + "emailNotRegistered": "Email is not registered.", + "errorSendingMail": "Error in sending mail.", + "passwordMismatches": "Password and Confirm password mismatches.", + "passwordChanges": "Password changes successfully.", + "OTPsent": "OTP is sent to your registered email." + }, + "pageNotFound": { + "title": "404 Not Found", + "talawaAdmin": "Talawa Admin", + "talawaUser": "Talawa User", + "404": "404", + "notFoundMsg": "Oops! The Page you requested was not found!", + "backToHome": "Back to Home" + }, + "orgContribution": { + "title": "Talawa Contributions", + "filterByName": "Filter by Name", + "filterByTransId": "Filter by Trans. ID", + "recentStats": "Recent Stats", + "contribution": "Contribution", + "orgname": "Enter Name", + "searchtransaction": "Enter Transaction ID" + }, + "contriStats": { + "recentContribution": "Recent Contribution", + "highestContribution": "Highest Contribution", + "totalContribution": "Total Contribution" + }, + "orgContriCards": { + "date": "Date", + "transactionId": "Transaction ID", + "amount": "Amount" + }, + "orgSettings": { + "title": "Settings", + "general": "General", + "actionItemCategories": "Action Item Categories", + "updateOrganization": "Update Organization", + "seeRequest": "See Request", + "noData": "No data", + "otherSettings": "Other Settings", + "changeLanguage": "Change Language", + "manageCustomFields": "Manage Custom Fields" + }, + "deleteOrg": { + "deleteOrganization": "Delete Organization", + "deleteSampleOrganization": "Delete Sample Organization", + "deleteMsg": "Do you want to delete this organization?", + "confirmDelete": "Confirm Delete", + "longDelOrgMsg": "By clicking on Delete Organization button the organization will be permanently deleted along with its events, tags and all related data.", + "successfullyDeletedSampleOrganization": "Successfully deleted sample Organization" + }, + "userUpdate": { + "appLanguageCode": "Default Language", + "userType": "User Type" + }, + "userPasswordUpdate": { + "previousPassword": "Previous Password", + "newPassword": "New Password", + "confirmNewPassword": "Confirm New Password", + "passCantBeEmpty": "Password can't be empty", + "passNoMatch": "New and Confirm password do not match." + }, + "orgDelete": { + "deleteOrg": "Delete Org" + }, + "membershipRequest": { + "accept": "Accept", + "reject": "Reject", + "memberAdded": "it is accepted" + }, + "orgUpdate": { + "city": "City", + "countryCode": "Country Code", + "line1": "Line 1", + "line2": "Line 2", + "postalCode": "Postal Code", + "dependentLocality": "Dependent Locality", + "sortingCode": "Sorting code", + "state": "State / Province", + "userRegistrationRequired": "User Registration Required", + "isVisibleInSearch": "Visible in Search", + "enterNameOrganization": "Enter Organization Name", + "successfulUpdated": "Organization updated successfully" + }, + "addOnRegister": { + "addNew": "Add New", + "addPlugin": "Add Plugin", + "pluginName": "Plugin Name", + "creatorName": "Creator Name", + "pluginDesc": "Plugin Description", + "pName": "Ex: Donations", + "cName": "Ex: john Doe", + "pDesc": "This Plugin enables UI for" + }, + "addOnStore": { + "title": "Add On Store", + "searchName": "Ex: Donations", + "search": "Search", + "enable": "Enabled", + "disable": "Disabled", + "pHeading": "Plugins", + "install": "Installed", + "available": "Available", + "pMessage": "Plugin does not exists", + "filter": "Filters" + }, + "addOnEntry": { + "enable": "Enabled", + "install": "Install", + "uninstall": "Uninstall", + "uninstallMsg": "This feature is now removed from your organization", + "installMsg": "This feature is now enabled in your organization" + }, + "memberDetail": { + "title": "User Details", + "addAdmin": "Add Admin", + "alreadyIsAdmin": "Member is already an Admin", + "organizations": "Organizations", + "events": "Events", + "role": "Role", + "createdOn": "Created on", + "main": "Main", + "firstName": "First name", + "lastName": "Last name", + "language": "Language", + "gender": "Gender", + "birthDate": "Birth Date", + "educationGrade": "Educational Grade", + "employmentStatus": "Employment Status", + "maritalStatus": "Marital Status", + "phone": "Phone", + "countryCode": "Country Code", + "state": "State", + "city": "City", + "personalInfoHeading": "Personal Information", + "contactInfoHeading": "Contact Information", + "actionsHeading": "Actions", + "personalDetailsHeading": "Profile Details", + "appLanguageCode": "Choose Language", + "deleteUser": "Delete User", + "pluginCreationAllowed": "Plugin creation allowed", + "created": "Created", + "adminForOrganizations": "Admin for organizations", + "membershipRequests": "Membership requests", + "adminForEvents": "Admin for events", + "addedAsAdmin": "User is added as admin.", + "userType": "User Type" + }, + "userLogin": { + "login": "Login", + "loginIntoYourAccount": "Login into your account", + "invalidDetailsMessage": "Please enter a valid email and password.", + "notAuthorised": "Sorry! you are not Authorised!", + "invalidCredentials": "Entered credentials are incorrect. Please enter valid credentials." + }, + "userRegister": { + "enterFirstName": "Enter your first name", + "enterLastName": "Enter your last name", + "enterConfirmPassword": "Enter Password to confirm", + "alreadyhaveAnAccount": "Already have an account?", + "login": "Login", + "afterRegister": "Successfully registered. Please wait for admin to approve your request.", + "passwordNotMatch": "Password doesn't match. Confirm Password and try again.", + "invalidDetailsMessage": "Please enter valid details." + }, + "userNavbar": { + "talawa": "Talawa", + "home": "Home", + "people": "People", + "events": "Events", + "chat": "Chat", + "donate": "Donate", + "language": "Language" + }, + "userOrganizations": { + "allOrganizations": "All Organizations", + "joinedOrganizations": "Joined Organizations", + "createdOrganizations": "Created Organizations", + "selectOrganization": "Select an organization", + "searchUsers": "Search users", + "nothingToShow": "Nothing to show here.", + "organizations": "Organizations" + }, + "userSidebarOrg": { + "yourOrganizations": "Your Organizations", + "noOrganizations": "You haven't joined any organization yet.", + "viewAll": "View all", + "talawaUserPortal": "Talawa User Portal", + "my organizations": "My Organizations", + "users": "Users", + "requests": "Requests", + "communityProfile": "Community Profile", + "logout": "Logout", + "settings": "Settings", + "chat": "Chat" + }, + "organizationSidebar": { + "viewAll": "View all", + "events": "Events", + "noEvents": "No Events to show", + "noMembers": "No Members to show" + }, + "postCard": { + "likes": "Likes", + "comments": "Comments", + "viewPost": "View Post", + "editPost": "Edit Post", + "postedOn": "Posted on {{date}}" + }, + "home": { + "posts": "Posts", + "post": "Post", + "title": "Title", + "textArea": "Something on your mind?", + "feed": "Feed", + "loading": "Loading", + "pinnedPosts": "Pinned Posts", + "yourFeed": "Your Feed", + "nothingToShowHere": "Nothing to show here", + "somethingOnYourMind": "Something on your mind?", + "addPost": "Add Post", + "startPost": "Start a post", + "media": "Media", + "event": "Event", + "article": "Article", + "postNowVisibleInFeed": "Post now visible in feed" + }, + "settings": { + "profileSettings": "Profile Settings", + "gender": "Gender", + "phoneNumber": "Phone Number", + "chooseFile": "Choose File", + "birthDate": "Birth Date", + "grade": "Educational Grade", + "empStatus": "Employment Status", + "maritalStatus": "Marital Status", + "state": "City/State", + "country": "Country", + "resetChanges": "Reset Changes", + "profileDetails": "Profile Details", + "deleteUserMessage": "By clicking on Delete User button your user will be permanently deleted along with its events, tags and all related data.", + "copyLink": "Copy Profile Link", + "deleteUser": "Delete User", + "otherSettings": "Other Settings", + "changeLanguage": "Change Language", + "sgender": "Select gender", + "gradePlaceholder": "Enter Grade", + "sEmpStatus": "Select employement status", + "female": "Female", + "male": "Male", + "employed": "Employed", + "other": "Other", + "sMaritalStatus": "Select marital status", + "unemployed": "Unemployed", + "married": "Married", + "single": "Single", + "widowed": "Widowed", + "divorced": "Divorced", + "engaged": "Engaged", + "separated": "Separated", + "grade1": "Grade 1", + "grade2": "Grade 2", + "grade3": "Grade 3", + "grade4": "Grade 4", + "grade5": "Grade 5", + "grade6": "Grade 6", + "grade7": "Grade 7", + "grade8": "Grade 8", + "grade9": "Grade 9", + "grade10": "Grade 10", + "grade11": "Grade 11", + "grade12": "Grade 12", + "graduate": "Graduate", + "kg": "KG", + "preKg": "Pre-KG", + "noGrade": "No Grade", + "fullTime": "Full Time", + "partTime": "Part Time", + "selectCountry": "Select a country", + "enterState": "Enter City or State" + }, + "donate": { + "donations": "Donations", + "searchDonations": "Search donations", + "donateForThe": "Donate for the", + "amount": "Amount", + "yourPreviousDonations": "Your Previous Donations", + "donate": "Donate", + "nothingToShow": "Nothing to show here.", + "success": "Donation Successful" + }, + "userEvents": { + "nothingToShow": "Nothing to show here.", + "createEvent": "Create Event", + "recurring": "Recurring Event", + "listView": "List View", + "calendarView": "Calendar View", + "allDay": "All Day", + "eventCreated": "Event created and posted successfully.", + "eventDetails": "Event Details", + "eventTitle": "Title", + "enterTitle": "Enter Title", + "enterDescription": "Enter Description", + "publicEvent": "Is Public", + "registerable": "Is Registerable", + "monthlyCalendarView": "Monthly Calendar", + "yearlyCalendarView": "Yearly Calender" + }, + "userEventCard": { + "starts": "Starts", + "ends": "Ends", + "creator": "Creator", + "alreadyRegistered": "Already registered" + }, + "advertisement": { + "title": "Advertisements", + "activeAds": "Active Campaigns", + "archievedAds": "Completed Campaigns", + "pMessage": "Ads not present for this campaign.", + "validLink": "Link is valid", + "invalidLink": "Link is invalid", + "Rname": "Enter name of Advertisement", + "Rtype": "Select type of Advertisement", + "Rmedia": "Provide media content to be displayed", + "RstartDate": "Select Start Date", + "RendDate": "Select End Date", + "RClose": "Close the window", + "addNew": "Create new advertisement", + "EXname": "Ex. Cookie Shop", + "EXlink": "Ex. http://yourwebsite.com/photo", + "createAdvertisement": "Create Advertisement", + "deleteAdvertisement": "Delete Advertisement", + "deleteAdvertisementMsg": "Do you want to remove this advertisement?", + "view": "View", + "editAdvertisement": "Edit Advertisement", + "advertisementDeleted": "Advertisement deleted successfully.", + "endDateGreaterOrEqual": "End Date should be greater than or equal to Start Date", + "advertisementCreated": "Advertisement created successfully." + }, + "userChat": { + "chat": "Chat", + "search": "Search", + "messages": "Messages", + "contacts": "Contacts" + }, + "userChatRoom": { + "selectContact": "Select a contact to start conversation", + "sendMessage": "Send Message" + }, + "orgProfileField": { + "loading": "Loading...", + "noCustomField": "No custom fields available", + "customFieldName": "Field Name", + "enterCustomFieldName": "Enter Field name", + "customFieldType": "Field Type", + "Remove Custom Field": "Remove Custom Field", + "fieldSuccessMessage": "Field added successfully", + "fieldRemovalSuccess": "Field removed successfully", + "String": "String", + "Boolean": "Boolean", + "Date": "Date", + "Number": "Number" + }, + "orgActionItemCategories": { + "enableButton": "Enable", + "disableButton": "Disable", + "updateActionItemCategory": "Update", + "actionItemCategoryName": "Name", + "actionItemCategoryDetails": "Action Item Category Details", + "enterName": "Enter Name", + "successfulCreation": "Action Item Category created successfully", + "successfulUpdation": "Action Item Category updated successfully", + "sameNameConflict": "Please change the name to make an update", + "categoryEnabled": "Action Item Category Enabled", + "categoryDisabled": "Action Item Category Disabled" + }, + "organizationVenues": { + "title": "Venues", + "addVenue": "Add Venue", + "venueDetails": "Venue Details", + "venueName": "Name of the Venue", + "enterVenueName": "Enter Venue Name", + "enterVenueDesc": "Enter Venue Description", + "capacity": "Capacity", + "enterVenueCapacity": "Enter Venue Capacity", + "image": "Venue Image", + "uploadVenueImage": "Upload Venue Image", + "createVenue": "Create Venue", + "venueAdded": "Venue added Successfully", + "editVenue": "Update Venue", + "venueUpdated": "Venue details updated successfully", + "sort": "Sort", + "highestCapacity": "Highest Capacity", + "lowestCapacity": "Lowest Capacity", + "noVenues": "No Venues Found!", + "view": "View", + "venueTitleError": "Venue title cannot be empty!", + "venueCapacityError": "Capacity must be a positive number!", + "searchBy": "Search By" + }, + "addMember": { + "title": "Add Member", + "addMembers": "Add Members", + "existingUser": "Existing User", + "newUser": "New User", + "searchFullName": "Search by Full Name", + "enterFirstName": "Enter First Name", + "enterLastName": "Enter Last Name", + "enterConfirmPassword": "Enter Confirm Password", + "organization": "Organization", + "invalidDetailsMessage": "Please provide all required details.", + "passwordNotMatch": "Passwords do not match.", + "addMember": "Add Member" + }, + "eventActionItems": { + "title": "Action Items", + "createActionItem": "Create Action Items", + "actionItemCategory": "Action Item Category", + "selectActionItemCategory": "Select an action item category", + "selectAssignee": "Select an assignee", + "assignee": "Assignee", + "assigner": "Assigner", + "preCompletionNotes": "Notes", + "postCompletionNotes": "Completion Notes", + "assignmentDate": "Assignment Date", + "status": "Status", + "actionItemActive": "Active", + "actionItemStatus": "Action Item Status", + "actionItemCompleted": "Action Item Completed", + "markCompletion": "Mark Completion", + "actionItemDetails": "Action Item Details", + "dueDate": "Due Date", + "completionDate": "Completion Date", + "editActionItem": "Edit Action Item", + "deleteActionItem": "Delete Action Item", + "deleteActionItemMsg": "Do you want to remove this action item?", + "successfulDeletion": "Action Item deleted successfully", + "successfulCreation": "Action Item created successfully", + "successfulUpdation": "Action Item updated successfully", + "notes": "Notes", + "save": "Save" + }, + "checkIn": { + "errorCheckingIn": "Error checking in", + "checkedInSuccessfully": "Checked in successfully" + }, + "eventRegistrantsModal": { + "errorAddingAttendee": "Error adding attendee", + "errorRemovingAttendee": "Error removing attendee" + } +} diff --git a/public/locales/fr/common.json b/public/locales/fr/common.json new file mode 100644 index 0000000000..250584da70 --- /dev/null +++ b/public/locales/fr/common.json @@ -0,0 +1,86 @@ +{ + "firstName": "Prénom", + "lastName": "Nom de famille", + "searchByName": "Rechercher par nom", + "loading": "Chargement...", + "endOfResults": "Fin des résultats", + "noResultsFoundFor": "Aucun résultat trouvé pour ", + "edit": "Modifier", + "admins": "Administrateurs", + "admin": "ADMINISTRATEUR", + "user": "UTILISATEUR", + "superAdmin": "SUPERADMIN", + "members": "Membres", + "logout": "Se déconnecter", + "login": "Se connecter", + "register": "Registre", + "menu": "Menu", + "settings": "Paramètres", + "users": "Utilisateurs", + "requests": "Demandes", + "OR": "OU", + "cancel": "Annuler", + "close": "Fermer", + "create": "Créer", + "delete": "Supprimer", + "done": "Fait", + "yes": "Oui", + "no": "Non", + "filter": "Filtre", + "search": "Recherche", + "description": "Description", + "saveChanges": "Sauvegarder les modifications", + "resetChanges": "Réinitialiser les modifications", + "displayImage": "Afficher l'image", + "enterEmail": "Entrez l'e-mail", + "emailAddress": "Adresse e-mail", + "email": "E-mail", + "name": "Nom", + "desc": "Description", + "enterPassword": "Entrer le mot de passe", + "password": "Mot de passe", + "confirmPassword": "Confirmez le mot de passe", + "forgotPassword": "Mot de passe oublié ?", + "talawaAdminPortal": "Portail d'administration Talawa", + "address": "Adresse", + "location": "Emplacement", + "enterLocation": "Entrez l'emplacement", + "joined": "Rejoint", + "startDate": "Date de début", + "endDate": "Date de fin", + "startTime": "Heure de début", + "endTime": "Heure de fin", + "My Organizations": "Mes Organisations", + "Dashboard": "Tableau de Bord", + "People": "Personnes", + "Events": "Événements", + "Venues": "Lieux", + "Action Items": "Éléments d'Action", + "Posts": "Publications", + "Block/Unblock": "Bloquer/Débloquer", + "Advertisement": "Publicité", + "Funds": "Fonds", + "Membership Requests": "Demandes d'Adhésion", + "Plugins": "Plugins", + "Plugin Store": "Magasin de Plugins", + "Settings": "Paramètres", + "createdOn": "Créé Le", + "createdBy": "Créé Par", + "usersRole": "Rôle de l'Utilisateur", + "changeRole": "Changer de Rôle", + "action": "Action", + "removeUser": "Supprimer l'Utilisateur", + "remove": "Supprimer", + "viewProfile": "Voir le Profil", + "profile": "Profil", + "noFiltersApplied": "Aucun filtre appliqué", + "manage": "Gérer", + "searchResultsFor": "Résultats de recherche pour {{text}}", + "none": "Aucun", + "sort": "Trier", + "Donate": "Faire un don", + "addedSuccessfully": "{{item}} ajouté avec succès", + "updatedSuccessfully": "{{item}} mis à jour avec succès", + "removedSuccessfully": "{{item}} supprimé avec succès", + "successfullyUpdated": "Mis à jour avec succès" +} diff --git a/public/locales/fr/errors.json b/public/locales/fr/errors.json new file mode 100644 index 0000000000..f5aea03266 --- /dev/null +++ b/public/locales/fr/errors.json @@ -0,0 +1,10 @@ +{ + "talawaApiUnavailable": "Le service Talawa-API n'est pas disponible !. ", + "notFound": "Pas trouvé", + "unknownError": "Une erreur inconnue est survenue. {{msg}}", + "notAuthorised": "Désolé! ", + "errorSendingMail": "Erreur lors de l'envoi du courrier", + "emailNotRegistered": "Email non enregistré", + "notFoundMsg": "Oops! ", + "errorOccurredCouldntCreate": "Une erreur s'est produite. Impossible de créer {{entity}}" +} diff --git a/public/locales/fr/translation.json b/public/locales/fr/translation.json new file mode 100644 index 0000000000..d5c084fcfe --- /dev/null +++ b/public/locales/fr/translation.json @@ -0,0 +1,984 @@ +{ + "loginPage": { + "title": "Administrateur Talawa", + "fromPalisadoes": "Une application open source réalisée par les bénévoles de la Fondation Palisadoes", + "userLogin": "Utilisateur en ligne", + "atleast_8_char_long": "Au moins 8 caractères", + "atleast_6_char_long": "Au moins 6 caractères", + "firstName_invalid": "Le prénom ne doit contenir que des lettres minuscules et majuscules", + "lastName_invalid": "Le nom de famille ne doit contenir que des lettres minuscules et majuscules", + "password_invalid": "Le mot de passe doit contenir au moins une lettre minuscule, une lettre majuscule, une valeur numérique et un caractère spécial", + "email_invalid": "L'e-mail doit contenir au moins 8 caractères", + "Password_and_Confirm_password_mismatches.": "Mot de passe et Confirmer les incompatibilités de mot de passe.", + "doNotOwnAnAccount": "Vous ne possédez pas de compte ?", + "captchaError": "Erreur CAPTCHA!", + "Please_check_the_captcha": "S'il vous plaît, vérifiez le captcha.", + "Something_went_wrong": "Quelque chose s'est mal passé. Veuillez réessayer plus tard.", + "passwordMismatches": "Mot de passe et Confirmer les incompatibilités de mot de passe.", + "fillCorrectly": "Remplissez correctement tous les détails.", + "successfullyRegistered": "Enregistré avec succès. ", + "lowercase_check": "Au moins une lettre minuscule", + "uppercase_check": "Au moins une lettre majuscule", + "numeric_value_check": "Au moins une valeur numérique", + "special_char_check": "Au moins un caractère spécial", + "selectOrg": "Sélectionnez une organisation", + "afterRegister": "Enregistré avec succès. " + }, + "userLoginPage": { + "title": "Administrateur Talawa", + "fromPalisadoes": "Une application open source réalisée par les bénévoles de la Fondation Palisadoes", + "atleast_8_char_long": "Au moins 8 caractères", + "Password_and_Confirm_password_mismatches.": "Mot de passe et Confirmer les incompatibilités de mot de passe.", + "doNotOwnAnAccount": "Vous ne possédez pas de compte ?", + "captchaError": "Erreur CAPTCHA!", + "Please_check_the_captcha": "S'il vous plaît, vérifiez le captcha.", + "Something_went_wrong": "Quelque chose s'est mal passé. Veuillez réessayer plus tard.", + "passwordMismatches": "Mot de passe et Confirmer les incompatibilités de mot de passe.", + "fillCorrectly": "Remplissez correctement tous les détails.", + "successfullyRegistered": "Enregistré avec succès. ", + "userLogin": "Utilisateur en ligne", + "afterRegister": "Enregistré avec succès. ", + "selectOrg": "Sélectionnez une organisation" + }, + "latestEvents": { + "eventCardTitle": "évènements à venir", + "eventCardSeeAll": "Voir tout", + "noEvents": "Aucun événement à venir" + }, + "latestPosts": { + "latestPostsTitle": "Derniers messages", + "seeAllLink": "Voir tout", + "noPostsCreated": "Aucun message créé" + }, + "listNavbar": { + "roles": "Les rôles" + }, + "leftDrawer": { + "my organizations": "Mes organisations", + "requests": "Demandes d'adhésion", + "communityProfile": "Profil de la communauté" + }, + "leftDrawerOrg": { + "Dashboard": "Tableau de bord", + "People": "Personnes", + "Events": "Événements", + "Contributions": "Contributions", + "Posts": "Des postes", + "Block/Unblock": "Bloquer/Débloquer", + "Plugins": "Plugins", + "Plugin Store": "Magasin de plugins", + "Advertisement": "Annonces", + "allOrganizations": "Toutes les organisations", + "yourOrganization": "Ton organisation", + "notification": "Notification", + "language": "Langue", + "notifications": "Notifications", + "spamsThe": "spamme le", + "group": "groupe", + "noNotifications": "Aucune notification" + }, + "orgList": { + "title": "Organisations Talawa", + "you": "Toi", + "designation": "Désignation", + "my organizations": "Mes organisations", + "createOrganization": "Créer une organisation", + "createSampleOrganization": "Créer un exemple d'organisation", + "city": "Ville", + "countryCode": "Code postal", + "dependentLocality": "Localité dépendante", + "line1": "Ligne 1", + "line2": "Ligne 2", + "postalCode": "Code Postal", + "sortingCode": "Code de tri", + "state": "État/Province", + "userRegistrationRequired": "Inscription de l'utilisateur requise", + "visibleInSearch": "Visible dans la recherche", + "enterName": "Entrez le nom", + "sort": "Trier", + "Latest": "Dernier", + "Earliest": "Le plus tôt", + "noOrgErrorTitle": "Organisations introuvables", + "sampleOrgDuplicate": "Un seul échantillon d’organisation autorisé", + "noOrgErrorDescription": "Veuillez créer une organisation via le tableau de bord", + "manageFeatures": "Gérer les fonctionnalités", + "manageFeaturesInfo": "Création réussie ! ", + "goToStore": "Accédez à la boutique de plugins", + "enableEverything": "Activer tout", + "sampleOrgSuccess": "Exemple d'organisation créée avec succès" + }, + "orgListCard": { + "manage": "Gérer", + "sampleOrganization": "Exemple d'organisation" + }, + "paginationList": { + "rowsPerPage": "lignes par page", + "all": "Tous" + }, + "requests": { + "title": "Demandes d'adhésion", + "sl_no": "Sl. ", + "accept": "Accepter", + "reject": "Rejeter", + "searchRequests": "Rechercher des demandes d'adhésion", + "noOrgError": "Organisations introuvables, veuillez créer une organisation via le tableau de bord", + "noRequestsFound": "Aucune demande d'adhésion trouvée", + "acceptedSuccessfully": "Demande acceptée avec succès", + "rejectedSuccessfully": "Demande rejetée avec succès", + "noOrgErrorTitle": "Organisations introuvables", + "noOrgErrorDescription": "Veuillez créer une organisation via le tableau de bord" + }, + "users": { + "title": "Rôles Talawa", + "joined_organizations": "Organisations rejointes", + "blocked_organizations": "Organisations bloquées", + "orgJoinedBy": "Organisations rejointes par", + "orgThatBlocked": "Organisations qui ont bloqué", + "hasNotJoinedAnyOrg": "n'a rejoint aucune organisation", + "isNotBlockedByAnyOrg": "n'est bloqué par aucune organisation", + "searchByOrgName": "Rechercher par nom d'organisation", + "view": "Voir", + "enterName": "Entrez le nom", + "loadingUsers": "Chargement des utilisateurs...", + "noUserFound": "Aucun utilisateur trouvé", + "sort": "Trier", + "Newest": "Le plus récent d'abord", + "Oldest": "Le plus âgé en premier", + "noOrgError": "Organisations introuvables, veuillez créer une organisation via le tableau de bord", + "roleUpdated": "Rôle mis à jour.", + "joinNow": "Adhérer maintenant", + "visit": "Visite", + "withdraw": "Largeur de tirage", + "removeUserFrom": "Supprimer l'Utilisateur de {{org}}", + "removeConfirmation": "Êtes-vous sûr de vouloir supprimer '{{name}}' de l'organisation '{{org}}' ?" + }, + "communityProfile": { + "title": "Profil de la communauté", + "editProfile": "Editer le profil", + "communityProfileInfo": "Ces détails apparaîtront sur l'écran de connexion/inscription pour vous et les membres de votre communauté.", + "communityName": "Nom de la communauté", + "wesiteLink": "Lien de site Web", + "logo": "Logo", + "social": "Liens vers les réseaux sociaux", + "url": "Entrer l'URL", + "profileChangedMsg": "Les détails du profil ont été mis à jour avec succès.", + "resetData": "Réinitialisez avec succès les détails du profil." + }, + "dashboard": { + "title": "Tableau de bord", + "about": "À propos", + "deleteThisOrganization": "Supprimer cette organisation", + "statistics": "Statistiques", + "posts": "Des postes", + "events": "Événements", + "blockedUsers": "Utilisateurs bloqués", + "viewAll": "Voir tout", + "upcomingEvents": "évènements à venir", + "noUpcomingEvents": "Aucun événement à venir", + "latestPosts": "Derniers messages", + "noPostsPresent": "Aucun message présent", + "membershipRequests": "Demandes d'adhésion", + "noMembershipRequests": "Aucune demande d'adhésion présente" + }, + "organizationPeople": { + "title": "Membres Talawa", + "filterByName": "Filtrer par nom", + "filterByLocation": "Filtrer par emplacement", + "filterByEvent": "Filtrer par événement", + "searchName": "Entrez le nom", + "searchevent": "Entrer l'événement", + "searchFullName": "Entrez le nom complet", + "people": "Personnes", + "sort": "Recherche par rôle", + "actions": "Actions", + "addMembers": "Ajouter des membres", + "existingUser": "Utilisateur existant", + "newUser": "Nouvel utilisateur", + "enterFirstName": "Entrez votre prénom", + "enterLastName": "Entrez votre nom de famille", + "enterConfirmPassword": "Entrez votre mot de passe pour confirmer", + "organization": "Organisation", + "invalidDetailsMessage": "Veuillez saisir des informations valides." + }, + "userListCard": { + "addAdmin": "Ajouter un administrateur", + "addedAsAdmin": "L'utilisateur est ajouté en tant qu'administrateur." + }, + "orgAdminListCard": { + "remove": "Retirer", + "removeAdmin": "Supprimer l'administrateur", + "removeAdminMsg": "Voulez-vous supprimer cet administrateur ?", + "adminRemoved": "L'administrateur est supprimé." + }, + "orgPeopleListCard": { + "remove": "Retirer", + "removeMember": "Supprimer un membre", + "removeMemberMsg": "Voulez-vous supprimer ce membre ?", + "memberRemoved": "Le membre est supprimé" + }, + "organizationEvents": { + "title": "Événements", + "filterByTitle": "Filtrer par titre", + "filterByLocation": "Filtrer par emplacement", + "filterByDescription": "Filtrer par description", + "addEvent": "Ajouter un évènement", + "eventDetails": "Détails de l'évènement", + "eventTitle": "Titre", + "startTime": "Heure de début", + "endTime": "Heure de fin", + "allDay": "Toute la journée", + "recurringEvent": "Événement récurrent", + "isPublic": "est public", + "isRegistrable": "Est enregistrable", + "createEvent": "Créer un évènement", + "enterFilter": "Entrer le filtre", + "enterTitle": "Entrez le titre", + "enterDescrip": "Entrez la description", + "eventLocation": "Entrez l'emplacement", + "searchEventName": "Rechercher le nom de l'événement", + "eventType": "Type d'événement", + "eventCreated": "Toutes nos félicitations! ", + "customRecurrence": "Récurrence personnalisée", + "repeatsEvery": "Se répète tous les", + "repeatsOn": "Répétition activée", + "ends": "Prend fin", + "never": "Jamais", + "on": "Sur", + "after": "Après", + "occurences": "événements" + }, + "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", + "active": "Actif", + "clearFilters": "Effacer les filtres", + "completed": "Complété", + "completionDate": "Date d'achèvement", + "createActionItem": "Créer un élément d'action", + "deleteActionItem": "Supprimer l'élément d'action", + "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", + "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" + }, + "organizationAgendaCategory": { + "agendaCategoryDetails": "Détails de la catégorie d'ordre du jour", + "updateAgendaCategory": "Mettre à jour la catégorie d'ordre du jour", + "title": "Catégories d'ordre du jour", + "name": "Catégorie", + "description": "Description", + "createdBy": "Créé par", + "options": "Options", + "createAgendaCategory": "Créer une catégorie d'ordre du jour", + "noAgendaCategories": "Aucune catégorie d'ordre du jour", + "update": "Mettre à jour", + "agendaCategoryCreated": "Catégorie d'ordre du jour créée avec succès", + "agendaCategoryUpdated": "Catégorie d'ordre du jour mise à jour avec succès", + "agendaCategoryDeleted": "Catégorie d'ordre du jour supprimée avec succès", + "deleteAgendaCategory": "Supprimer la catégorie d'ordre du jour", + "deleteAgendaCategoryMsg": "Souhaitez-vous supprimer cette catégorie d'ordre du jour ?" + }, + "agendaItems": { + "agendaItemDetails": "Détails du point de l'ordre du jour", + "updateAgendaItem": "Mettre à jour le point de l'ordre du jour", + "title": "Titre", + "enterTitle": "Entrer le titre", + "sequence": "Ordre", + "description": "Description", + "enterDescription": "Entrer la description", + "category": "Catégorie de l'ordre du jour", + "attachments": "Pièces jointes", + "attachmentLimit": "Ajouter un fichier image ou vidéo jusqu'à 10 Mo", + "fileSizeExceedsLimit": "La taille du fichier dépasse la limite de 10 Mo", + "urls": "URL", + "url": "Ajouter un lien vers l'URL", + "enterUrl": "https://example.com", + "invalidUrl": "Veuillez saisir une URL valide", + "link": "Lien", + "createdBy": "Créé par", + "regular": "Régulier", + "note": "Note", + "duration": "Durée", + "enterDuration": "mm:ss", + "options": "Options", + "createAgendaItem": "Créer un point à l'ordre du jour", + "noAgendaItems": "Aucun point à l'ordre du jour", + "selectAgendaItemCategory": "Sélectionner une catégorie de point de l'ordre du jour", + "update": "Mettre à jour", + "delete": "Supprimer", + "agendaItemCreated": "Point de l'ordre du jour créé avec succès", + "agendaItemUpdated": "Point de l'ordre du jour mis à jour avec succès", + "agendaItemDeleted": "Point de l'ordre du jour supprimé avec succès", + "deleteAgendaItem": "Supprimer le point de l'ordre du jour", + "deleteAgendaItemMsg": "Voulez-vous supprimer ce point de l'ordre du jour ?" + }, + "eventListCard": { + "deleteEvent": "Supprimer l'événement", + "deleteEventMsg": "Voulez-vous supprimer cet événement ?", + "editEvent": "Modifier l'événement", + "eventTitle": "Titre", + "alreadyRegistered": "Déjà enregistré", + "startTime": "Heure de début", + "endTime": "Heure de fin", + "allDay": "Toute la journée", + "recurringEvent": "Événement récurrent", + "isPublic": "est public", + "isRegistrable": "Est enregistrable", + "updatePost": "Mettre à jour le message", + "eventDetails": "Détails de l'évènement", + "eventDeleted": "Événement supprimé avec succès.", + "eventUpdated": "Événement mis à jour avec succès.", + "thisInstance": "Cette instance", + "thisAndFollowingInstances": "Instances présentes et suivantes", + "allInstances": "Toutes les instances", + "customRecurrence": "Récurrence personnalisée", + "repeatsEvery": "Se répète tous les", + "repeatsOn": "Répétition activée", + "ends": "Prend fin", + "never": "Jamais", + "on": "Sur", + "after": "Après", + "occurences": "événements" + }, + "funds": { + "title": "Fonds", + "createFund": "Créer un fonds", + "fundName": "Nom du fonds", + "fundId": "ID de référence du fonds", + "taxDeductible": "Déductible d'impôt", + "default": "Par défaut", + "archived": "Archivé", + "fundCreate": "Créer un fonds", + "fundUpdate": "Mettre à jour le fonds", + "fundDelete": "Supprimer le fonds", + "searchByName": "Rechercher par nom", + "noFundsFound": "Aucun fonds trouvé", + "createdBy": "Créé par", + "createdOn": "Créé le", + "status": "Statut", + "fundCreated": "Fonds créé avec succès", + "fundUpdated": "Fonds mis à jour avec succès", + "fundDeleted": "Fonds supprimé avec succès", + "deleteFundMsg": "Êtes-vous sûr de vouloir supprimer ce fonds ?", + "createdLatest": "Créé le plus récemment", + "createdEarliest": "Créé le plus tôt", + "viewCampaigns": "Voir les campagnes" + }, + "fundCampaign": { + "title": "Campagnes de collecte de fonds", + "campaignName": "Nom de la campagne", + "campaignOptions": "Options", + "fundingGoal": "Objectif de financement", + "addCampaign": "Ajouter une campagne", + "createdCampaign": "Campagne créée avec succès", + "updatedCampaign": "Campagne mise à jour avec succès", + "deletedCampaign": "Campagne supprimée avec succès", + "deleteCampaignMsg": "Êtes-vous sûr de vouloir supprimer cette campagne ?", + "noCampaigns": "Aucune campagne trouvée", + "createCampaign": "Créer une campagne", + "updateCampaign": "Mettre à jour la campagne", + "deleteCampaign": "Supprimer la campagne", + "currency": "Devise", + "selectCurrency": "Sélectionner la devise", + "searchFullName": "Rechercher par nom", + "viewPledges": "Voir les promesses de dons", + "noCampaignsFound": "Aucune campagne trouvée", + "latestEndDate": "Dernière date de fin", + "earliestEndDate": "Date de fin la plus ancienne", + "lowestGoal": "Objectif le plus bas", + "highestGoal": "Objectif le plus élevé" + }, + "pledges": { + "title": "Engagements de campagne de financement", + "pledgeAmount": "Montant de la promesse de don", + "pledgeOptions": "Possibilités", + "pledgeCreated": "Engagement créé avec succès", + "pledgeUpdated": "Engagement mis à jour avec succès", + "pledgeDeleted": "Engagement supprimé avec succès", + "addPledge": "Ajouter un engagement", + "createPledge": "Créer un engagement", + "currency": "Devise", + "selectCurrency": "Sélectionnez la devise", + "updatePledge": "Engagement de mise à jour", + "deletePledge": "Supprimer l'engagement", + "amount": "Montant", + "editPledge": "Modifier l'engagement", + "deletePledgeMsg": "Etes-vous sûr de vouloir supprimer cet engagement ?", + "noPledges": "Aucun engagement trouvé", + "searchPledger": "Rechercher par les bailleurs de fonds", + "highestAmount": "Montant le plus élevé", + "lowestAmount": "Montant le plus bas", + "latestEndDate": "Date de fin la plus récente", + "earliestEndDate": "Date de fin la plus proche", + "campaigns": "Campagnes", + "pledges": "Promesses de dons", + "endsOn": "Se termine le", + "raisedAmount": "Montant collecté", + "pledgedAmount": "Montant promis" + }, + "orgPost": { + "title": "Des postes", + "searchPost": "Rechercher un article", + "posts": "Des postes", + "createPost": "Créer un message", + "postDetails": "Détails du message", + "postTitle1": "Écrivez le titre du message", + "postTitle": "Titre", + "addMedia": "Télécharger des médias", + "information": "Information", + "information1": "Écrire les informations du message", + "addPost": "Ajouter un message", + "searchTitle": "Recherche par titre", + "searchText": "Recherche par texte", + "ptitle": "Titre de l'article", + "postDes": "De quoi veux-tu parler ?", + "Title": "Titre", + "Text": "Texte", + "searchBy": "Recherché par", + "Oldest": "Le plus âgé en premier", + "Latest": "Dernier premier", + "sortPost": "Trier le message", + "tag": " Votre navigateur ne prend pas en charge la balise vidéo", + "postCreatedSuccess": "Toutes nos félicitations! ", + "pinPost": "Épingler le message", + "Next": "Page suivante", + "Previous": "Page précédente" + }, + "postNotFound": { + "post": "Poste", + "not found!": "Pas trouvé!", + "organization": "Organisation", + "post not found!": "Message introuvable !", + "organization not found!": "Organisation introuvable !" + }, + "userNotFound": { + "not found!": "Pas trouvé!", + "roles": "Les rôles", + "user not found!": "Utilisateur non trouvé!", + "member not found!": "Membre introuvable!", + "admin not found!": "Administrateur introuvable !", + "roles not found!": "Rôles introuvables !" + }, + "orgPostCard": { + "author": "Auteur", + "imageURL": "URL de l'image", + "videoURL": "URL de la vidéo", + "deletePost": "Supprimer le message", + "deletePostMsg": "Voulez-vous supprimer ce message?", + "editPost": "Modifier le message", + "postTitle": "Titre", + "postTitle1": "Modifier le titre du message", + "information1": "Modifier les informations du message", + "information": "Information", + "image": "Image", + "video": "Vidéo", + "updatePost": "Mettre à jour le message", + "postDeleted": "Message supprimé avec succès.", + "postUpdated": "Post mis à jour avec succès.", + "tag": " Votre navigateur ne prend pas en charge la balise vidéo", + "pin": "Épingler le message" + }, + "blockUnblockUser": { + "title": "Bloquer/débloquer un utilisateur", + "pageName": "Bloquer/Débloquer", + "listOfUsers": "Liste des utilisateurs qui ont spammé", + "block_unblock": "Bloquer/Débloquer", + "unblock": "Débloquer", + "block": "Bloc", + "orgName": "Entrez le nom", + "blockedSuccessfully": "Utilisateur bloqué avec succès", + "Un-BlockedSuccessfully": "Utilisateur débloqué avec succès", + "allMembers": "Tous les membres", + "blockedUsers": "Utilisateurs bloqués", + "searchByFirstName": "Recherche par prénom", + "searchByLastName": "Rechercher par nom de famille", + "noSpammerFound": "Aucun spammeur trouvé" + }, + "eventManagement": { + "title": "Gestion d'événements", + "dashboard": "Tableau de bord", + "registrants": "Inscrits", + "eventActions": "Actions d'événement", + "eventAgendas": "Ordres du jour des événements", + "eventStats": "Statistiques des événements", + "to": "À" + }, + "forgotPassword": { + "title": "Talawa Mot de passe oublié", + "registeredEmail": "Email enregistré", + "getOtp": "Obtenir OTP", + "enterOtp": "Entrez OTP", + "enterNewPassword": "Entrez un nouveau mot de passe", + "cofirmNewPassword": "Confirmer le nouveau mot de passe", + "changePassword": "Changer le mot de passe", + "backToLogin": "Retour connexion", + "userOtp": "par exemple. ", + "emailNotRegistered": "L'e-mail n'est pas enregistré.", + "errorSendingMail": "Erreur lors de l'envoi du courrier.", + "passwordMismatches": "Mot de passe et Confirmer les incompatibilités de mot de passe.", + "passwordChanges": "Le mot de passe a été modifié avec succès.", + "OTPsent": "OTP est envoyé à votre adresse e-mail enregistrée." + }, + "pageNotFound": { + "404": "404", + "title": "404 introuvable", + "talawaAdmin": "Administrateur Talawa", + "talawaUser": "Utilisateur Talawa", + "notFoundMsg": "Oops! ", + "backToHome": "De retour à la maison" + }, + "orgContribution": { + "title": "Contributions de Talawa", + "filterByName": "Filtrer par nom", + "filterByTransId": "Filtrer par Trans. ", + "recentStats": "Statistiques récentes", + "contribution": "Contribution", + "orgname": "Entrez le nom", + "searchtransaction": "Entrez l'ID de la transaction" + }, + "contriStats": { + "recentContribution": "Contribution récente", + "highestContribution": "Contribution la plus élevée", + "totalContribution": "Contribution totale" + }, + "orgContriCards": { + "date": "Date", + "transactionId": "identifiant de transaction", + "amount": "Montant" + }, + "orgSettings": { + "title": "Paramètres", + "general": "Général", + "actionItemCategories": "Catégories d'éléments d'action", + "updateOrganization": "Mettre à jour l'organisation", + "seeRequest": "Voir la demande", + "noData": "Pas de données", + "otherSettings": "Autres réglages", + "changeLanguage": "Changer de langue", + "manageCustomFields": "Gérer les champs personnalisés" + }, + "deleteOrg": { + "deleteOrganization": "Supprimer l'organisation", + "deleteSampleOrganization": "Supprimer un exemple d'organisation", + "deleteMsg": "Voulez-vous supprimer cette organisation ?", + "confirmDelete": "Confirmation de la suppression", + "longDelOrgMsg": "En cliquant sur le bouton Supprimer l'organisation, l'organisation sera définitivement supprimée ainsi que ses événements, balises et toutes les données associées.", + "successfullyDeletedSampleOrganization": "Exemple d'organisation supprimé avec succès" + }, + "userUpdate": { + "appLanguageCode": "Langage par défaut", + "userType": "Type d'utilisateur" + }, + "userPasswordUpdate": { + "previousPassword": "Mot de passe précédent", + "newPassword": "nouveau mot de passe", + "confirmNewPassword": "Confirmer le nouveau mot de passe", + "passCantBeEmpty": "Le mot de passe ne peut pas être vide", + "passNoMatch": "Le nouveau mot de passe et la confirmation du mot de passe ne correspondent pas." + }, + "orgDelete": { + "deleteOrg": "Supprimer l'organisation" + }, + "membershipRequest": { + "accept": "Accepter", + "reject": "Rejeter", + "memberAdded": "c'est accepté" + }, + "orgUpdate": { + "city": "Ville", + "countryCode": "Code postal", + "line1": "Ligne 1", + "line2": "Ligne 2", + "postalCode": "Code Postal", + "dependentLocality": "Localité dépendante", + "sortingCode": "Code de tri", + "state": "État/Province", + "userRegistrationRequired": "Inscription de l'utilisateur requise", + "isVisibleInSearch": "Visible dans la recherche", + "enterNameOrganization": "Entrez le nom de l'organisation", + "successfulUpdated": "Organisation mise à jour avec succès" + }, + "addOnRegister": { + "addNew": "Ajouter un nouveau", + "addPlugin": "Ajouter un plugin", + "pluginName": "Nom du plugin", + "creatorName": "Nom du créateur", + "pluginDesc": "Description du plugin", + "pName": "Ex : Dons", + "cName": "Ex : John Doe", + "pDesc": "Ce plugin active l'interface utilisateur pour" + }, + "addOnStore": { + "title": "Ajouter sur la boutique", + "searchName": "Ex : Dons", + "search": "Rechercher", + "enable": "Activé", + "disable": "Désactivé", + "pHeading": "Plugins", + "install": "installée", + "available": "Disponible", + "pMessage": "Le plugin n'existe pas" + }, + "addOnEntry": { + "enable": "Activé", + "install": "Installer", + "uninstall": "Désinstaller", + "uninstallMsg": "Cette fonctionnalité est désormais supprimée de votre organisation", + "installMsg": "Cette fonctionnalité est désormais activée dans votre organisation" + }, + "memberDetail": { + "title": "Détails de l'utilisateur", + "addAdmin": "Ajouter un administrateur", + "alreadyIsAdmin": "Le membre est déjà un administrateur", + "organizations": "Organisations", + "events": "Événements", + "role": "Rôle", + "createdOn": "Créé sur", + "main": "Principal", + "firstName": "Prénom", + "lastName": "Nom de famille", + "language": "Langue", + "gender": "Genre", + "birthDate": "Date de naissance", + "educationGrade": "Niveau d'éducation", + "employmentStatus": "Statut d'emploi", + "maritalStatus": "État civil", + "phone": "Téléphone", + "countryCode": "Code postal", + "state": "État", + "city": "Ville", + "personalInfoHeading": "Informations personnelles", + "contactInfoHeading": "Coordonnées", + "actionsHeading": "Actions", + "personalDetailsHeading": "Détails du profil", + "appLanguageCode": "Choisissez la langue", + "deleteUser": "Supprimer l'utilisateur", + "pluginCreationAllowed": "Création de plugin autorisée", + "created": "Créé", + "adminForOrganizations": "Administrateur pour les organisations", + "membershipRequests": "Demandes d'adhésion", + "adminForEvents": "Administrateur pour les événements", + "addedAsAdmin": "L'utilisateur est ajouté en tant qu'administrateur.", + "userType": "Type d'utilisateur" + }, + "userLogin": { + "login": "Se connecter", + "loginIntoYourAccount": "Connectez-vous à votre compte", + "invalidDetailsMessage": "Veuillez entrer un email et un mot de passe valides.", + "notAuthorised": "Désolé! ", + "invalidCredentials": "Les informations d'identification saisies sont incorrectes. " + }, + "userRegister": { + "enterFirstName": "Entrez votre prénom", + "enterLastName": "Entrez votre nom de famille", + "enterConfirmPassword": "Entrez votre mot de passe pour confirmer", + "alreadyhaveAnAccount": "Vous avez déjà un compte?", + "login": "Se connecter", + "afterRegister": "Enregistré avec succès. ", + "passwordNotMatch": "Le mot de passe ne correspond pas. ", + "invalidDetailsMessage": "Veuillez saisir des informations valides." + }, + "userNavbar": { + "talawa": "Talawa", + "home": "Maison", + "people": "Personnes", + "events": "Événements", + "chat": "Chat", + "donate": "Faire un don", + "language": "Langue" + }, + "userOrganizations": { + "allOrganizations": "Toutes les organisations", + "joinedOrganizations": "Organisations rejointes", + "createdOrganizations": "Organisations créées", + "selectOrganization": "Sélectionnez une organisation", + "searchUsers": "Rechercher des utilisateurs", + "nothingToShow": "Rien à montrer ici.", + "organizations": "Organisations" + }, + "userSidebarOrg": { + "yourOrganizations": "Vos organisations", + "noOrganizations": "Vous n'avez encore rejoint aucune organisation.", + "viewAll": "Voir tout", + "talawaUserPortal": "Portail utilisateur Talawa", + "my organizations": "Mes organisations", + "communityProfile": "Profil de la communauté" + }, + "organizationSidebar": { + "viewAll": "Voir tout", + "events": "Événements", + "noEvents": "Aucun événement à afficher", + "noMembers": "Aucun membre à afficher" + }, + "postCard": { + "likes": "Aime", + "comments": "commentaires", + "viewPost": "Voir le message", + "editPost": "Modifier le message", + "postedOn": "Publié le {{date}}" + }, + "home": { + "posts": "Des postes", + "post": "Poste", + "title": "Titre", + "textArea": "Quelque chose vous préoccupe ?", + "feed": "Alimentation", + "loading": "Chargement", + "pinnedPosts": "Messages épinglés", + "yourFeed": "Votre flux", + "nothingToShowHere": "Rien à montrer ici", + "somethingOnYourMind": "Quelque chose vous préoccupe ?", + "addPost": "Ajouter un message", + "startPost": "Démarrer un message", + "media": "Médias", + "event": "Événement", + "article": "Article", + "postNowVisibleInFeed": "Le post est maintenant visible dans le fil d'actualité" + }, + "settings": { + "profileSettings": "Paramètres de profil", + "gender": "Genre", + "phoneNumber": "Numéro de téléphone", + "chooseFile": "Choisir le fichier", + "birthDate": "Date de naissance", + "grade": "Niveau d'éducation", + "empStatus": "Statut d'emploi", + "maritalStatus": "État civil", + "state": "Ville/État", + "country": "Pays", + "resetChanges": "Réinitialiser les modifications", + "profileDetails": "Détails du profil", + "deleteUserMessage": "En cliquant sur le bouton Supprimer l'utilisateur, votre utilisateur sera définitivement supprimé ainsi que ses événements, balises et toutes les données associées.", + "copyLink": "Copier le lien du profil", + "deleteUser": "Supprimer l'utilisateur", + "otherSettings": "Autres réglages", + "changeLanguage": "Changer de langue", + "sgender": "Sélectionnez le sexe", + "gradePlaceholder": "Entrez la note", + "sEmpStatus": "Sélectionnez le statut d'emploi", + "female": "Femelle", + "male": "Mâle", + "employed": "Employé", + "other": "Autre", + "sMaritalStatus": "Sélectionnez l'état civil", + "unemployed": "Sans emploi", + "married": "Marié", + "single": "Célibataire", + "widowed": "Veuf", + "divorced": "Divorcé", + "engaged": "Engagé", + "separated": "Séparé", + "grade1": "1re année", + "grade2": "2e année", + "grade3": "3e année", + "grade4": "Niveau 4", + "grade5": "Niveau 5", + "grade6": "6ème année", + "grade7": "7e année", + "grade8": "8e année", + "grade9": "9e année", + "grade10": "10 e année", + "grade11": "11e année", + "grade12": "12 e année", + "graduate": "Diplômé", + "kg": "KG", + "preKg": "Pré-KG", + "noGrade": "Aucune note", + "fullTime": "À temps plein", + "partTime": "À temps partiel", + "selectCountry": "Choisissez un pays", + "enterState": "Entrez la ville ou l'état" + }, + "donate": { + "donations": "Des dons", + "searchDonations": "Rechercher des dons", + "donateForThe": "Faites un don pour le", + "amount": "Montant", + "yourPreviousDonations": "Vos dons précédents", + "donate": "Faire un don", + "nothingToShow": "Rien à montrer ici.", + "success": "Don réussi" + }, + "userEvents": { + "nothingToShow": "Rien à montrer ici.", + "createEvent": "Créer un évènement", + "recurring": "Événement récurrent", + "startTime": "Heure de début", + "endTime": "Heure de fin", + "listView": "Vue en liste", + "calendarView": "Vue du calendrier", + "allDay": "Toute la journée", + "eventCreated": "Événement créé et publié avec succès.", + "eventDetails": "Détails de l'évènement", + "eventTitle": "Titre", + "enterTitle": "Entrez le titre", + "enterDescription": "Entrez la description", + "enterLocation": "Entrez l'emplacement", + "publicEvent": "est public", + "registerable": "Est enregistrable", + "monthlyCalendarView": "Calendrier mensuel", + "yearlyCalendarView": "Calendrier annuel" + }, + "userEventCard": { + "starts": "Départs", + "ends": "Prend fin", + "creator": "Créateur", + "alreadyRegistered": "Déjà enregistré" + }, + "advertisement": { + "title": "Annonces", + "activeAds": "Campagnes actives", + "archievedAds": "Campagnes terminées", + "pMessage": "Annonces non présentes pour cette campagne.", + "validLink": "Le lien est valide", + "invalidLink": "Le lien n'est pas valide", + "Rname": "Entrez le nom de l'annonce", + "Rtype": "Sélectionnez le type de publicité", + "Rmedia": "Fournir du contenu multimédia à afficher", + "RstartDate": "Sélectionnez la date de début", + "RendDate": "Sélectionnez la date de fin", + "RClose": "Ferme la fenêtre", + "addNew": "Créer une nouvelle annonce", + "EXname": "Ex. ", + "EXlink": "Ex. ", + "createAdvertisement": "Créer une publicité", + "deleteAdvertisement": "Supprimer la publicité", + "deleteAdvertisementMsg": "Voulez-vous supprimer cette publicité ?", + "view": "Voir", + "editAdvertisement": "Modifier l'annonce", + "advertisementDeleted": "Publicité supprimée avec succès.", + "endDateGreaterOrEqual": "La date de fin doit être supérieure ou égale à la date de début", + "advertisementCreated": "Publicité créée avec succès." + }, + "userChat": { + "chat": "Chat", + "contacts": "Contacts" + }, + "userChatRoom": { + "selectContact": "Sélectionnez un contact pour démarrer la conversation", + "sendMessage": "Envoyer le message" + }, + "orgProfileField": { + "loading": "Chargement...", + "noCustomField": "Aucun champ personnalisé disponible", + "customFieldName": "Nom de domaine", + "enterCustomFieldName": "Entrez le nom du champ", + "customFieldType": "Type de champ", + "Remove Custom Field": "Supprimer le champ personnalisé", + "fieldSuccessMessage": "Champ ajouté avec succès", + "fieldRemovalSuccess": "Champ supprimé avec succès", + "String": "Chaîne", + "Boolean": "Booléen", + "Date": "Date", + "Number": "Nombre" + }, + "orgActionItemCategories": { + "enableButton": "Activer", + "disableButton": "Désactiver", + "updateActionItemCategory": "Mise à jour", + "actionItemCategoryName": "Nom", + "actionItemCategoryDetails": "Détails de la catégorie d'élément d'action", + "enterName": "Entrez le nom", + "successfulCreation": "Catégorie d'élément d'action créée avec succès", + "successfulUpdation": "Catégorie d'élément d'action mise à jour avec succès", + "sameNameConflict": "Veuillez changer le nom pour effectuer une mise à jour", + "categoryEnabled": "Catégorie d'élément d'action activée", + "categoryDisabled": "Catégorie d'élément d'action désactivée" + }, + "organizationVenues": { + "title": "Lieux", + "addVenue": "Ajouter un lieu", + "venueDetails": "Détails du lieu", + "venueName": "Nom du lieu", + "enterVenueName": "Entrez le nom du lieu", + "enterVenueDesc": "Entrez la description du lieu", + "capacity": "Capacité", + "enterVenueCapacity": "Entrez la capacité du site", + "image": "Image du lieu", + "uploadVenueImage": "Télécharger l'image du lieu", + "createVenue": "Créer un lieu", + "venueAdded": "Lieu ajouté avec succès", + "editVenue": "Mettre à jour le lieu", + "venueUpdated": "Les détails du lieu ont été mis à jour avec succès", + "sort": "Trier", + "highestCapacity": "Capacité la plus élevée", + "lowestCapacity": "Capacité la plus basse", + "noVenues": "Aucun lieu trouvé !", + "view": "Voir", + "venueTitleError": "Le titre du lieu ne peut pas être vide !", + "venueCapacityError": "La capacité doit être un nombre positif !", + "searchBy": "Recherché par" + }, + "addMember": { + "title": "Ajouter un membre", + "addMembers": "Ajouter des membres", + "existingUser": "Utilisateur existant", + "newUser": "Nouvel utilisateur", + "searchFullName": "Rechercher par nom complet", + "enterFirstName": "Entrez votre prénom", + "enterLastName": "Entrer le nom de famille", + "enterConfirmPassword": "Entrez Confirmer le mot de passe", + "organization": "Organisation", + "invalidDetailsMessage": "Veuillez fournir tous les détails requis.", + "passwordNotMatch": "Les mots de passe ne correspondent pas.", + "addMember": "Ajouter un membre" + }, + "eventActionItems": { + "title": "Éléments d'action", + "createActionItem": "Créer des éléments d'action", + "actionItemCategory": "Catégorie d'élément d'action", + "selectActionItemCategory": "Sélectionnez une catégorie d'élément d'action", + "selectAssignee": "Sélectionnez un responsable", + "preCompletionNotes": "Remarques", + "postCompletionNotes": "Notes d'achèvement", + "actionItemDetails": "Détails de l'action", + "dueDate": "Date d'échéance", + "completionDate": "Date d'achèvement", + "editActionItem": "Modifier l'élément d'action", + "deleteActionItem": "Supprimer l'élément d'action", + "deleteActionItemMsg": "Voulez-vous supprimer cette action ?", + "successfulDeletion": "Élément d'action supprimé avec succès", + "successfulCreation": "Élément d'action créé avec succès", + "successfulUpdation": "Élément d'action mis à jour avec succès", + "notes": "Remarques", + "assignee": "Cessionnaire", + "assigner": "Assigner", + "assignmentDate": "Date d'affectation", + "status": "Statut", + "actionItemActive": "Actif", + "actionItemStatus": "Statut de l'action", + "actionItemCompleted": "Élément d'action terminé", + "markCompletion": "Marquer l'achèvement", + "save": "Sauvegarder" + }, + "checkIn": { + "errorCheckingIn": "Erreur lors de l'enregistrement", + "checkedInSuccessfully": "Enregistrement réussi" + }, + "eventRegistrantsModal": { + "errorAddingAttendee": "Erreur lors de l'ajout du participant", + "errorRemovingAttendee": "Erreur lors de la suppression du participant" + } +} diff --git a/public/locales/hi/common.json b/public/locales/hi/common.json new file mode 100644 index 0000000000..3889f73e59 --- /dev/null +++ b/public/locales/hi/common.json @@ -0,0 +1,86 @@ +{ + "firstName": "पहला नाम", + "lastName": "उपनाम", + "searchByName": "नाम से खोजें", + "loading": "लोड हो रहा है...", + "endOfResults": "परिणाम का अंत", + "noResultsFoundFor": "का कोई परिणाम नहीं मिला ", + "edit": "संपादन करना", + "admins": "व्यवस्थापक", + "admin": "व्यवस्थापक", + "user": "उपयोगकर्ता", + "superAdmin": "सुपरएडमिन", + "members": "सदस्यों", + "logout": "लॉग आउट", + "login": "लॉग इन करें", + "register": "पंजीकरण करवाना", + "menu": "मेन्यू", + "settings": "समायोजन", + "users": "उपयोगकर्ताओं", + "requests": "अनुरोध", + "OR": "या", + "cancel": "रद्द करना", + "close": "बंद करना", + "create": "बनाएं", + "delete": "मिटाना", + "done": "हो गया", + "yes": "हाँ", + "no": "नहीं", + "filter": "फ़िल्टर", + "search": "खोज", + "description": "विवरण", + "saveChanges": "परिवर्तनों को सुरक्षित करें", + "resetChanges": "परिवर्तनों को रीसेट करें", + "displayImage": "प्रदर्शन छवि", + "enterEmail": "ईमेल दर्ज करें", + "emailAddress": "मेल पता", + "email": "ईमेल", + "name": "नाम", + "desc": "विवरण", + "enterPassword": "पास वर्ड दर्ज करें", + "password": "पासवर्ड", + "confirmPassword": "पासवर्ड की पुष्टि कीजिये", + "forgotPassword": "पासवर्ड भूल गए ?", + "talawaAdminPortal": "तलावा एडमिन पोर्टल", + "address": "पता", + "location": "जगह", + "enterLocation": "स्थान दर्ज करें", + "joined": "में शामिल हो गए", + "startDate": "आरंभ करने की तिथि", + "endDate": "अंतिम तिथि", + "startTime": "समय शुरू", + "endTime": "अंत समय", + "My Organizations": "मेरे संगठन", + "Dashboard": "डैशबोर्ड", + "People": "लोग", + "Events": "कार्यक्रम", + "Venues": "स्थल", + "Action Items": "कार्य आइटम", + "Posts": "पोस्ट", + "Block/Unblock": "ब्लॉक/अनब्लॉक", + "Advertisement": "विज्ञापन", + "Funds": "निधि", + "Membership Requests": "सदस्यता अनुरोध", + "Plugins": "प्लगइन्स", + "Plugin Store": "प्लगइन स्टोर", + "Settings": "सेटिंग्स", + "createdOn": "बनाया गया", + "createdBy": "के द्वारा बनाया गया", + "usersRole": "उपयोगकर्ता की भूमिका", + "changeRole": "भूमिका बदलें", + "action": "क्रिया", + "removeUser": "उपयोगकर्ता हटाएं", + "remove": "हटाएं", + "viewProfile": "प्रोफ़ाइल देखें", + "profile": "प्रोफ़ाइल", + "noFiltersApplied": "कोई फ़िल्टर लागू नहीं हैं", + "manage": "प्रबंधित करें", + "searchResultsFor": "{{text}} के लिए खोज परिणाम", + "none": "कोई नहीं", + "sort": "क्रम से लगाना", + "Donate": "दान करें", + "addedSuccessfully": "{{item}} सफलतापूर्वक जोड़ा गया", + "updatedSuccessfully": "{{item}} सफलतापूर्वक अपडेट किया गया", + "removedSuccessfully": "{{item}} सफलतापूर्वक हटाया गया", + "successfullyUpdated": "सफलतापूर्वक अपडेट किया गया" +} diff --git a/public/locales/hi/errors.json b/public/locales/hi/errors.json new file mode 100644 index 0000000000..c31c72fa34 --- /dev/null +++ b/public/locales/hi/errors.json @@ -0,0 +1,10 @@ +{ + "talawaApiUnavailable": "तलवा-एपीआई सेवा उपलब्ध नहीं है! ", + "notFound": "नहीं मिला", + "unknownError": "एक अज्ञात त्रुटि हुई। {{msg}}", + "notAuthorised": "क्षमा मांगना! ", + "errorSendingMail": "मेल भेजने में त्रुटि", + "emailNotRegistered": "ईमेल पंजीकृत नहीं है", + "notFoundMsg": "उफ़! ", + "errorOccurredCouldntCreate": "एक त्रुटि हुई। {{entity}} नहीं बना सके" +} diff --git a/public/locales/hi/translation.json b/public/locales/hi/translation.json new file mode 100644 index 0000000000..ab850249e2 --- /dev/null +++ b/public/locales/hi/translation.json @@ -0,0 +1,984 @@ +{ + "loginPage": { + "title": "तलावा प्रशासन", + "fromPalisadoes": "पैलिसाडोज़ फाउंडेशन के स्वयंसेवकों द्वारा एक खुला स्रोत एप्लिकेशन", + "userLogin": "उपयोगकर्ता लॉगिन", + "atleast_8_char_long": "कम से कम 8 अक्षर लंबा", + "atleast_6_char_long": "कम से कम 6 अक्षर लंबा", + "firstName_invalid": "प्रथम नाम में केवल छोटे और बड़े अक्षर होने चाहिए", + "lastName_invalid": "अंतिम नाम में केवल छोटे और बड़े अक्षर होने चाहिए", + "password_invalid": "पासवर्ड में कम से कम एक लोअरकेस अक्षर, एक अपरकेस अक्षर, एक संख्यात्मक मान और एक विशेष अक्षर होना चाहिए", + "email_invalid": "ईमेल में कम से कम 8 अक्षर होने चाहिए", + "Password_and_Confirm_password_mismatches.": "पासवर्ड और पासवर्ड बेमेल होने की पुष्टि करें।", + "doNotOwnAnAccount": "क्या आपके पास कोई खाता नहीं है?", + "captchaError": "कैप्चा त्रुटि!", + "Please_check_the_captcha": "कृपया, कैप्चा जांचें।", + "Something_went_wrong": "कुछ ग़लत हो गया, कृपया कुछ देर बाद प्रयास करें।", + "passwordMismatches": "पासवर्ड और पासवर्ड बेमेल होने की पुष्टि करें।", + "fillCorrectly": "सभी विवरण सही-सही भरें।", + "successfullyRegistered": "पंजीकरण सफलतापूर्वक हो गया है। ", + "lowercase_check": "कम से कम एक छोटा अक्षर", + "uppercase_check": "कम से कम एक बड़ा अक्षर", + "numeric_value_check": "कम से कम एक संख्यात्मक मान निर्धारित करें", + "special_char_check": "कम से कम एक विशेष पात्र", + "selectOrg": "एक संगठन चुनें", + "afterRegister": "पंजीकरण सफलतापूर्वक हो गया है। " + }, + "userLoginPage": { + "title": "तलावा प्रशासन", + "fromPalisadoes": "पैलिसाडोज़ फाउंडेशन के स्वयंसेवकों द्वारा एक खुला स्रोत एप्लिकेशन", + "atleast_8_char_long": "कम से कम 8 अक्षर लंबा", + "Password_and_Confirm_password_mismatches.": "पासवर्ड और पासवर्ड बेमेल होने की पुष्टि करें।", + "doNotOwnAnAccount": "क्या आपके पास कोई खाता नहीं है?", + "captchaError": "कैप्चा त्रुटि!", + "Please_check_the_captcha": "कृपया, कैप्चा जांचें।", + "Something_went_wrong": "कुछ ग़लत हो गया, कृपया कुछ देर बाद प्रयास करें।", + "passwordMismatches": "पासवर्ड और पासवर्ड बेमेल होने की पुष्टि करें।", + "fillCorrectly": "सभी विवरण सही-सही भरें।", + "successfullyRegistered": "पंजीकरण सफलतापूर्वक हो गया है। ", + "userLogin": "उपयोगकर्ता लॉगिन", + "afterRegister": "पंजीकरण सफलतापूर्वक हो गया है। ", + "selectOrg": "एक संगठन चुनें" + }, + "latestEvents": { + "eventCardTitle": "आगामी कार्यक्रम", + "eventCardSeeAll": "सभी देखें", + "noEvents": "कोई आगामी ईवेंट नहीं" + }, + "latestPosts": { + "latestPostsTitle": "नवीनतम पोस्ट", + "seeAllLink": "सभी देखें", + "noPostsCreated": "कोई पोस्ट नहीं बनाई गई" + }, + "listNavbar": { + "roles": "भूमिकाएँ" + }, + "leftDrawer": { + "my organizations": "मेरे संगठन", + "requests": "सदस्यता अनुरोध", + "communityProfile": "सामुदायिक प्रोफ़ाइल" + }, + "leftDrawerOrg": { + "Dashboard": "डैशबोर्ड", + "People": "लोग", + "Events": "आयोजन", + "Contributions": "योगदान", + "Posts": "पदों", + "Block/Unblock": "ब्लॉक/अनब्लॉक करें", + "Plugins": "प्लग-इन", + "Plugin Store": "प्लगइन स्टोर", + "Advertisement": "विज्ञापनों", + "allOrganizations": "सभी संगठन", + "yourOrganization": "आपकी संगठन", + "notification": "अधिसूचना", + "language": "भाषा", + "notifications": "सूचनाएं", + "spamsThe": "स्पैम करता है", + "group": "समूह", + "noNotifications": "कोई सूचनाएं नहीं" + }, + "orgList": { + "title": "तलावा संगठन", + "you": "आप", + "designation": "पद का नाम", + "my organizations": "मेरे संगठन", + "createOrganization": "संगठन बनाएं", + "createSampleOrganization": "नमूना संगठन बनाएं", + "city": "शहर", + "countryCode": "कंट्री कोड", + "dependentLocality": "आश्रित इलाका", + "line1": "लाइन 1", + "line2": "लाइन 2", + "postalCode": "डाक कोड", + "sortingCode": "कोड क्रमबद्ध करना", + "state": "राज्य/प्रान्त", + "userRegistrationRequired": "उपयोगकर्ता पंजीकरण आवश्यक", + "visibleInSearch": "खोज में दृश्यमान", + "enterName": "नाम दर्ज करें", + "sort": "क्रम से लगाना", + "Latest": "नवीनतम", + "Earliest": "जल्द से जल्द", + "noOrgErrorTitle": "संगठन नहीं मिले", + "sampleOrgDuplicate": "केवल एक नमूना संगठन को अनुमति दी गई", + "noOrgErrorDescription": "कृपया डैशबोर्ड के माध्यम से एक संगठन बनाएं", + "manageFeatures": "सुविधाओं को प्रबंधित करें", + "manageFeaturesInfo": "सृजन सफल! ", + "goToStore": "प्लगइन स्टोर पर जाएँ", + "enableEverything": "सब कुछ सक्षम करें", + "sampleOrgSuccess": "नमूना संगठन सफलतापूर्वक बनाया गया" + }, + "orgListCard": { + "manage": "प्रबंधित करना", + "sampleOrganization": "नमूना संगठन" + }, + "paginationList": { + "rowsPerPage": "प्रति पृष्ठ पंक्तियाँ", + "all": "सभी" + }, + "requests": { + "title": "सदस्यता अनुरोध", + "sl_no": "क्र.सं. ", + "accept": "स्वीकार करना", + "reject": "अस्वीकार करना", + "searchRequests": "सदस्यता अनुरोध खोजें", + "noOrgError": "संगठन नहीं मिला, कृपया डैशबोर्ड के माध्यम से एक संगठन बनाएं", + "noRequestsFound": "कोई सदस्यता अनुरोध नहीं मिला", + "acceptedSuccessfully": "अनुरोध सफलतापूर्वक स्वीकार किया गया", + "rejectedSuccessfully": "अनुरोध सफलतापूर्वक अस्वीकार कर दिया गया", + "noOrgErrorTitle": "संगठन नहीं मिले", + "noOrgErrorDescription": "कृपया डैशबोर्ड के माध्यम से एक संगठन बनाएं" + }, + "users": { + "title": "तलावा भूमिकाएँ", + "joined_organizations": "संगठनों से जुड़े", + "blocked_organizations": "अवरुद्ध संगठन", + "orgJoinedBy": "संगठनों से जुड़े", + "orgThatBlocked": "वे संगठन जिन्होंने अवरुद्ध किया", + "hasNotJoinedAnyOrg": "किसी भी संगठन में शामिल नहीं हुआ है", + "isNotBlockedByAnyOrg": "किसी भी संगठन द्वारा अवरुद्ध नहीं किया गया है", + "searchByOrgName": "संगठन के नाम से खोजें", + "view": "देखना", + "enterName": "नाम दर्ज करें", + "loadingUsers": "उपयोगकर्ता लोड हो रहे हैं...", + "noUserFound": "कोई उपयोगकर्ता नहीं मिला", + "sort": "क्रम से लगाना", + "Newest": "नवीनतम पहले", + "Oldest": "सबसे पुराना पहले", + "noOrgError": "संगठन नहीं मिला, कृपया डैशबोर्ड के माध्यम से एक संगठन बनाएं", + "roleUpdated": "भूमिका अद्यतन की गई.", + "joinNow": "अब शामिल हों", + "visit": "मिलने जाना", + "withdraw": "चौड़ाई निकालना", + "removeUserFrom": "{{org}} से उपयोगकर्ता हटाएं", + "removeConfirmation": "क्या आप वाकई '{{org}}' संगठन से '{{name}}' को हटाना चाहते हैं?" + }, + "communityProfile": { + "title": "सामुदायिक प्रोफ़ाइल", + "editProfile": "प्रोफ़ाइल संपादित करें", + "communityProfileInfo": "ये विवरण आपके और आपके समुदाय के सदस्यों के लिए लॉगिन/साइनअप स्क्रीन पर दिखाई देंगे", + "communityName": "समुदाय का नाम", + "wesiteLink": "वेबसाइट की लिंक", + "logo": "प्रतीक चिन्ह", + "social": "सोशल मीडिया लिंक", + "url": "यू आर एल दर्ज करो", + "profileChangedMsg": "प्रोफ़ाइल विवरण सफलतापूर्वक अपडेट किया गया.", + "resetData": "प्रोफ़ाइल विवरण सफलतापूर्वक रीसेट करें।" + }, + "dashboard": { + "title": "डैशबोर्ड", + "about": "के बारे में", + "deleteThisOrganization": "इस संगठन को हटाएँ", + "statistics": "आंकड़े", + "posts": "पदों", + "events": "आयोजन", + "blockedUsers": "रोके गए उपयोगकर्ता", + "viewAll": "सभी को देखें", + "upcomingEvents": "आगामी कार्यक्रम", + "noUpcomingEvents": "कोई आगामी ईवेंट नहीं", + "latestPosts": "नवीनतम पोस्ट", + "noPostsPresent": "कोई पोस्ट मौजूद नहीं", + "membershipRequests": "सदस्यता अनुरोध", + "noMembershipRequests": "कोई सदस्यता अनुरोध मौजूद नहीं है" + }, + "organizationPeople": { + "title": "तलवा सदस्य", + "filterByName": "नाम से फ़िल्टर करें", + "filterByLocation": "स्थान के अनुसार फ़िल्टर करें", + "filterByEvent": "इवेंट के अनुसार फ़िल्टर करें", + "searchName": "नाम दर्ज करें", + "searchevent": "इवेंट दर्ज करें", + "searchFullName": "पूरा नाम दर्ज करें", + "people": "लोग", + "sort": "भूमिका के आधार पर खोजें", + "actions": "कार्रवाई", + "addMembers": "सदस्य जोड़ें", + "existingUser": "मौजूदा उपयोगकर्ता", + "newUser": "नए उपयोगकर्ता", + "enterFirstName": "अपना पहला नाम दर्ज करें", + "enterLastName": "अपना अंतिम नाम दर्ज करें", + "enterConfirmPassword": "पुष्टि करने के लिए अपना पासवर्ड दर्ज करें", + "organization": "संगठन", + "invalidDetailsMessage": "कृपया वैध विवरण दर्ज करें." + }, + "userListCard": { + "addAdmin": "व्यवस्थापक जोड़ें", + "addedAsAdmin": "उपयोगकर्ता को व्यवस्थापक के रूप में जोड़ा गया है." + }, + "orgAdminListCard": { + "remove": "निकालना", + "removeAdmin": "व्यवस्थापक हटाएँ", + "removeAdminMsg": "क्या आप इस व्यवस्थापक को हटाना चाहते हैं?", + "adminRemoved": "व्यवस्थापक को हटा दिया गया है." + }, + "orgPeopleListCard": { + "remove": "निकालना", + "removeMember": "सदस्य हटाएँ", + "removeMemberMsg": "क्या आप इस सदस्य को हटाना चाहते हैं?", + "memberRemoved": "सदस्य को हटा दिया गया है" + }, + "organizationEvents": { + "title": "आयोजन", + "filterByTitle": "शीर्षक के अनुसार फ़िल्टर करें", + "filterByLocation": "स्थान के अनुसार फ़िल्टर करें", + "filterByDescription": "विवरण के अनुसार फ़िल्टर करें", + "addEvent": "कार्यक्रम जोड़ें", + "eventDetails": "घटना की जानकारी", + "eventTitle": "शीर्षक", + "startTime": "समय शुरू", + "endTime": "अंत समय", + "allDay": "पूरे दिन", + "recurringEvent": "पुनरावर्ती ईवेंट", + "isPublic": "सार्वजनिक है", + "isRegistrable": "पंजीकरण योग्य है", + "createEvent": "कार्यक्रम बनाएँ", + "enterFilter": "फ़िल्टर दर्ज करें", + "enterTitle": "शीर्षक दर्ज करें", + "enterDescrip": "विवरण दर्ज करें", + "eventLocation": "स्थान दर्ज करें", + "searchEventName": "ईवेंट का नाम खोजें", + "eventType": "घटना प्रकार", + "eventCreated": "बधाई हो! ", + "customRecurrence": "कस्टम पुनरावृत्ति", + "repeatsEvery": "प्रत्येक को दोहराता है", + "repeatsOn": "पर दोहराता है", + "ends": "समाप्त होता है", + "never": "कभी नहीं", + "on": "पर", + "after": "बाद", + "occurences": "घटनाओं" + }, + "organizationActionItems": { + "actionItemCategory": "कार्य आइटम श्रेणी", + "actionItemDetails": "कार्रवाई मद विवरण", + "actionItemCompleted": "कार्य आइटम पूर्ण हुआ", + "assignee": "संपत्ति-भागी", + "assigner": "असाइनर", + "assignmentDate": "असाइनमेंट दिनांक", + "active": "सक्रिय", + "clearFilters": "फ़िल्टर साफ़ करें", + "completed": "पुरा होना।", + "completionDate": "पूरा करने की तिथि", + "createActionItem": "कार्रवाई आइटम बनाएं", + "deleteActionItem": "क्रिया आइटम हटाएँ", + "deleteActionItemMsg": "क्या आप इस क्रिया आइटम को हटाना चाहते हैं?", + "details": "विवरण", + "dueDate": "नियत तारीख", + "earliest": "जल्द से जल्द", + "editActionItem": "क्रिया आइटम संपादित करें", + "isCompleted": "पुरा होना।", + "latest": "नवीनतम", + "makeActive": "सक्रिय", + "noActionItems": "कोई एक्शन आइटम नहीं", + "options": "विकल्प", + "preCompletionNotes": "समापन पूर्व नोट्स", + "actionItemActive": "सक्रिय", + "markCompletion": "पूर्णता चिह्नित करें", + "actionItemStatus": "कार्रवाई मद स्थिति", + "postCompletionNotes": "समापन के बाद के नोट्स", + "selectActionItemCategory": "एक क्रिया आइटम श्रेणी का चयन करें", + "selectAssignee": "एक समनुदेशिती का चयन करें", + "status": "स्थिति", + "successfulCreation": "कार्रवाई आइटम सफलतापूर्वक बनाया गया", + "successfulUpdation": "कार्रवाई आइटम सफलतापूर्वक अपडेट किया गया", + "successfulDeletion": "कार्रवाई आइटम सफलतापूर्वक हटा दिया गया", + "title": "एक्शन आइटम्स" + }, + "organizationAgendaCategory": { + "agendaCategoryDetails": "एजेंडा श्रेणी विवरण", + "updateAgendaCategory": "एजेंडा श्रेणी अपडेट करें", + "title": "एजेंडा श्रेणियाँ", + "name": "श्रेणी", + "description": "विवरण", + "createdBy": "द्वारा बनाया गया", + "options": "विकल्प", + "createAgendaCategory": "एजेंडा श्रेणी बनाएं", + "noAgendaCategories": "कोई एजेंडा श्रेणी नहीं", + "update": "अपडेट करें", + "agendaCategoryCreated": "एजेंडा श्रेणी सफलतापूर्वक बनाई गई", + "agendaCategoryUpdated": "एजेंडा श्रेणी सफलतापूर्वक अपडेट की गई", + "agendaCategoryDeleted": "एजेंडा श्रेणी सफलतापूर्वक हटा दी गई", + "deleteAgendaCategory": "एजेंडा श्रेणी हटाएं", + "deleteAgendaCategoryMsg": "क्या आप इस एजेंडा श्रेणी को हटाना चाहते हैं?" + }, + "agendaItems": { + "agendaItemDetails": "एजेंडा आइटम विवरण", + "updateAgendaItem": "एजेंडा आइटम अपडेट करें", + "title": "शीर्षक", + "enterTitle": "शीर्षक दर्ज करें", + "sequence": "क्रम", + "description": "विवरण", + "enterDescription": "विवरण दर्ज करें", + "category": "एजेंडा श्रेणी", + "attachments": "संलग्नक", + "attachmentLimit": "10MB तक कोई भी छवि फ़ाइल या वीडियो फ़ाइल जोड़ें", + "fileSizeExceedsLimit": "फ़ाइल का आकार सीमा 10MB से अधिक है", + "urls": "URL", + "url": "URL में लिंक जोड़ें", + "enterUrl": "https://example.com", + "invalidUrl": "कृपया एक वैध URL दर्ज करें", + "link": "लिंक", + "createdBy": "बनाया गया द्वारा", + "regular": "नियमित", + "note": "नोट", + "duration": "अवधि", + "enterDuration": "मिमी:से", + "options": "विकल्प", + "createAgendaItem": "एजेंडा आइटम बनाएं", + "noAgendaItems": "कोई एजेंडा आइटम नहीं", + "selectAgendaItemCategory": "एजेंडा आइटम श्रेणी चुनें", + "update": "अपडेट करें", + "delete": "हटाएं", + "agendaItemCreated": "एजेंडा आइटम सफलतापूर्वक बनाया गया", + "agendaItemUpdated": "एजेंडा आइटम सफलतापूर्वक अपडेट किया गया", + "agendaItemDeleted": "एजेंडा आइटम सफलतापूर्वक हटा दिया गया", + "deleteAgendaItem": "एजेंडा आइटम हटाएं", + "deleteAgendaItemMsg": "क्या आप इस एजेंडा आइटम को हटाना चाहते हैं?" + }, + "eventListCard": { + "deleteEvent": "ईवेंट हटाएँ", + "deleteEventMsg": "क्या आप इस ईवेंट को हटाना चाहते हैं?", + "editEvent": "इवेंट संपादित करें", + "eventTitle": "शीर्षक", + "alreadyRegistered": "पहले से ही पंजीकृत", + "startTime": "समय शुरू", + "endTime": "अंत समय", + "allDay": "पूरे दिन", + "recurringEvent": "पुनरावर्ती ईवेंट", + "isPublic": "सार्वजनिक है", + "isRegistrable": "पंजीकरण योग्य है", + "updatePost": "पोस्ट अपडेट करें", + "eventDetails": "घटना की जानकारी", + "eventDeleted": "ईवेंट सफलतापूर्वक हटा दिया गया.", + "eventUpdated": "इवेंट सफलतापूर्वक अपडेट किया गया.", + "thisInstance": "यह उदाहरण", + "thisAndFollowingInstances": "यह और निम्नलिखित उदाहरण", + "allInstances": "सभी उदाहरण", + "customRecurrence": "कस्टम पुनरावृत्ति", + "repeatsEvery": "प्रत्येक को दोहराता है", + "repeatsOn": "पर दोहराता है", + "ends": "समाप्त होता है", + "never": "कभी नहीं", + "on": "पर", + "after": "बाद", + "occurences": "घटनाओं" + }, + "funds": { + "title": "फंड", + "createFund": "फंड बनाएँ", + "fundName": "फंड का नाम", + "fundId": "फंड (संदर्भ) आईडी", + "taxDeductible": "कर ड्यूटी कटाई", + "default": "डिफ़ॉल्ट", + "archived": "आर्काइव", + "fundCreate": "फंड बनाएँ", + "fundUpdate": "फंड अपडेट करें", + "fundDelete": "फंड को हटाएँ", + "searchByName": "नाम से खोजें", + "noFundsFound": "कोई फंड नहीं मिला", + "createdBy": "द्वारा बनाया गया", + "createdOn": "पर बनाया गया", + "status": "स्थिति", + "fundCreated": "फंड सफलतापूर्वक बनाया गया", + "fundUpdated": "फंड सफलतापूर्वक अपडेट किया गया", + "fundDeleted": "फंड सफलतापूर्वक हटाया गया", + "deleteFundMsg": "क्या आप वाकई इस फंड को हटाना चाहते हैं?", + "createdLatest": "सबसे पहले बनाया", + "createdEarliest": "सबसे जल्दी बनाया", + "viewCampaigns": "कैम्पेंस देखें" + }, + "fundCampaign": { + "title": "फंडरेजिंग कैंपेन", + "campaignName": "कैंपेन का नाम", + "campaignOptions": "विकल्प", + "fundingGoal": "फंडिंग उद्देश्य", + "addCampaign": "कैंपेन जोड़ें", + "createdCampaign": "कैंपेन सफलतापूर्वक बनाई गई", + "updatedCampaign": "कैंपेन सफलतापूर्वक अपडेट की गई", + "deletedCampaign": "कैंपेन सफलतापूर्वक हटा दी गई", + "deleteCampaignMsg": "क्या आप वाकई इस कैंपेन को हटाना चाहते हैं?", + "noCampaigns": "कोई कैंपेन नहीं मिली", + "createCampaign": "कैंपेन बनाएँ", + "updateCampaign": "कैंपेन अपडेट करें", + "deleteCampaign": "कैंपेन को हटाएं", + "currency": "मुद्रा", + "selectCurrency": "मुद्रा का चयन करें", + "searchFullName": "नाम से खोजें", + "viewPledges": "प्लेज देखें", + "noCampaignsFound": "कोई कैंपेन नहीं मिली", + "latestEndDate": "अंतिम समाप्ति तिथि", + "earliestEndDate": "सबसे पहली समाप्ति तिथि", + "lowestGoal": "सबसे कम उद्देश्य", + "highestGoal": "सबसे ऊंचा उद्देश्य" + }, + "pledges": { + "title": "निधि अभियान प्रतिज्ञाएँ", + "pledgeAmount": "प्रतिज्ञा राशि", + "pledgeOptions": "विकल्प", + "pledgeCreated": "प्रतिज्ञा सफलतापूर्वक बनाई गई", + "pledgeUpdated": "प्रतिज्ञा सफलतापूर्वक अद्यतन की गई", + "pledgeDeleted": "प्रतिज्ञा सफलतापूर्वक हटा दी गई", + "addPledge": "प्रतिज्ञा जोड़ें", + "createPledge": "प्रतिज्ञा बनाएँ", + "currency": "मुद्रा", + "selectCurrency": "मुद्रा चुनें", + "updatePledge": "प्रतिज्ञा अद्यतन करें", + "deletePledge": "प्रतिज्ञा हटाएँ", + "amount": "मात्रा", + "editPledge": "प्रतिज्ञा संपादित करें", + "deletePledgeMsg": "क्या आप वाकई इस प्रतिज्ञा को हटाना चाहते हैं?", + "noPledges": "कोई प्रतिज्ञा नहीं मिली", + "searchPledger": "प्लेजर्स के द्वारा खोजें", + "highestAmount": "सबसे अधिक राशि", + "lowestAmount": "सबसे कम राशि", + "latestEndDate": "नवीनतम समाप्ति तिथि", + "earliestEndDate": "सबसे प्रारंभिक समाप्ति तिथि", + "campaigns": "अभियान", + "pledges": "प्रतिज्ञाएँ", + "endsOn": "पर समाप्त होता है", + "raisedAmount": "उठाया गया राशि", + "pledgedAmount": "प्रतिबद्ध राशि" + }, + "orgPost": { + "title": "पदों", + "searchPost": "पोस्ट खोजें", + "posts": "पदों", + "createPost": "पोस्ट बनाएं", + "postDetails": "पोस्ट विवरण", + "postTitle1": "पोस्ट का शीर्षक लिखें", + "postTitle": "शीर्षक", + "addMedia": "मीडिया अपलोड करें", + "information": "जानकारी", + "information1": "पोस्ट की जानकारी लिखें", + "addPost": "पोस्ट जोड़ें", + "searchTitle": "शीर्षक से खोजें", + "searchText": "पाठ द्वारा खोजें", + "ptitle": "शीर्षक पोस्ट करें", + "postDes": "तुम्हें किस बारे में बात करनी है?", + "Title": "शीर्षक", + "Text": "मूलपाठ", + "searchBy": "खोज से", + "Oldest": "सबसे पुराना पहले", + "Latest": "नवीनतम प्रथम", + "sortPost": "पोस्ट क्रमबद्ध करें", + "tag": " आपका ब्राउज़र में वीडियो टैग समर्थित नहीं है", + "postCreatedSuccess": "बधाई हो! ", + "pinPost": "पिन पद", + "Next": "अगला पृष्ठ", + "Previous": "पिछला पृष्ठ" + }, + "postNotFound": { + "post": "डाक", + "not found!": "नहीं मिला!", + "organization": "संगठन", + "post not found!": "पोस्ट नहीं मिली!", + "organization not found!": "संगठन नहीं मिला!" + }, + "userNotFound": { + "not found!": "नहीं मिला!", + "roles": "भूमिकाएँ", + "user not found!": "उपयोगकर्ता नहीं मिला!", + "member not found!": "सदस्य अनुपस्थित!", + "admin not found!": "व्यवस्थापक नहीं मिला!", + "roles not found!": "भूमिकाएँ नहीं मिलीं!" + }, + "orgPostCard": { + "author": "लेखक", + "imageURL": "छवि यूआरएल", + "videoURL": "वीडियो यूआरएल", + "deletePost": "पोस्ट को हटाएं", + "deletePostMsg": "क्या आप इस पोस्ट को हटाना चाहते हैं?", + "editPost": "संपादित पोस्ट", + "postTitle": "शीर्षक", + "postTitle1": "पोस्ट का शीर्षक संपादित करें", + "information1": "पोस्ट की जानकारी संपादित करें", + "information": "जानकारी", + "image": "छवि", + "video": "वीडियो", + "updatePost": "पोस्ट अपडेट करें", + "postDeleted": "पोस्ट सफलतापूर्वक हटा दी गई.", + "postUpdated": "पोस्ट सफलतापूर्वक अपडेट किया गया.", + "tag": " आपका ब्राउज़र में वीडियो टैग समर्थित नहीं है", + "pin": "पिन पद" + }, + "blockUnblockUser": { + "title": "उपयोगकर्ता को ब्लॉक/अनब्लॉक करें", + "pageName": "ब्लॉक/अनब्लॉक करें", + "listOfUsers": "स्पैम भेजने वाले उपयोगकर्ताओं की सूची", + "block_unblock": "ब्लॉक/अनब्लॉक करें", + "unblock": "अनवरोधित", + "block": "अवरोध पैदा करना", + "orgName": "नाम दर्ज करें", + "blockedSuccessfully": "उपयोगकर्ता को सफलतापूर्वक अवरोधित किया गया", + "Un-BlockedSuccessfully": "उपयोगकर्ता को सफलतापूर्वक अन-अवरुद्ध किया गया", + "allMembers": "सभी सदस्य", + "blockedUsers": "रोके गए उपयोगकर्ता", + "searchByFirstName": "प्रथम नाम से खोजें", + "searchByLastName": "अंतिम नाम से खोजें", + "noSpammerFound": "कोई स्पैमर नहीं मिला" + }, + "eventManagement": { + "title": "इवेंट मैनेजमेंट", + "dashboard": "डैशबोर्ड", + "registrants": "कुलसचिव", + "eventActions": "घटना क्रियाएँ", + "eventAgendas": "इवेंट एजेंडा", + "eventStats": "घटना सांख्यिकी", + "to": "को" + }, + "forgotPassword": { + "title": "तलावा पासवर्ड भूल गए", + "registeredEmail": "पंजीकृत ईमेल", + "getOtp": "ओटीपी प्राप्त करें", + "enterOtp": "ओटीपी दर्ज करें", + "enterNewPassword": "नया पासवर्ड दर्ज करें", + "cofirmNewPassword": "नए पासवर्ड की पुष्टि करें", + "changePassword": "पासवर्ड बदलें", + "backToLogin": "लॉगिन पर वापस जाएं", + "userOtp": "जैसे ", + "emailNotRegistered": "ईमेल पंजीकृत नहीं है.", + "errorSendingMail": "मेल भेजने में त्रुटि.", + "passwordMismatches": "पासवर्ड और पासवर्ड बेमेल होने की पुष्टि करें।", + "passwordChanges": "पासवर्ड सफलतापूर्वक बदल गया.", + "OTPsent": "ओटीपी आपके पंजीकृत ईमेल पर भेजा जाता है।" + }, + "pageNotFound": { + "404": "404", + "title": "404 नहीं मिला", + "talawaAdmin": "तलावा प्रशासन", + "talawaUser": "तलावा उपयोगकर्ता", + "notFoundMsg": "उफ़! ", + "backToHome": "घर वापिस जा रहा हूँ" + }, + "orgContribution": { + "title": "तलावा योगदान", + "filterByName": "नाम से फ़िल्टर करें", + "filterByTransId": "ट्रांस द्वारा फ़िल्टर करें। ", + "recentStats": "हाल के आँकड़े", + "contribution": "योगदान", + "orgname": "नाम दर्ज करें", + "searchtransaction": "लेनदेन आईडी दर्ज करें" + }, + "contriStats": { + "recentContribution": "हालिया योगदान", + "highestContribution": "सर्वोच्च योगदान", + "totalContribution": "कुल योगदान" + }, + "orgContriCards": { + "date": "तारीख", + "transactionId": "लेन-देन आईडी", + "amount": "मात्रा" + }, + "orgSettings": { + "title": "समायोजन", + "general": "सामान्य", + "actionItemCategories": "कार्रवाई आइटम श्रेणियाँ", + "updateOrganization": "संगठन अद्यतन करें", + "seeRequest": "अनुरोध देखें", + "noData": "कोई डेटा नहीं", + "otherSettings": "अन्य सेटिंग", + "changeLanguage": "भाषा बदलें", + "manageCustomFields": "कस्टम फ़ील्ड प्रबंधित करें" + }, + "deleteOrg": { + "deleteOrganization": "संगठन हटाएँ", + "deleteSampleOrganization": "नमूना संगठन हटाएँ", + "deleteMsg": "क्या आप इस संगठन को हटाना चाहते हैं?", + "confirmDelete": "हटाने की पुष्टि करें", + "longDelOrgMsg": "संगठन हटाएं बटन पर क्लिक करने से संगठन अपने ईवेंट, टैग और सभी संबंधित डेटा के साथ स्थायी रूप से हटा दिया जाएगा।", + "successfullyDeletedSampleOrganization": "नमूना संगठन सफलतापूर्वक हटा दिया गया" + }, + "userUpdate": { + "appLanguageCode": "डिफ़ॉल्ट भाषा", + "userType": "उपयोगकर्ता का प्रकार" + }, + "userPasswordUpdate": { + "previousPassword": "पिछला पासवर्ड", + "newPassword": "नया पासवर्ड", + "confirmNewPassword": "नए पासवर्ड की पुष्टि करें", + "passCantBeEmpty": "पासवर्ड खाली नहीं हो सकता", + "passNoMatch": "नया पासवर्ड और पुष्टि पासवर्ड मेल नहीं खाते।" + }, + "orgDelete": { + "deleteOrg": "संगठन हटाएं" + }, + "membershipRequest": { + "accept": "स्वीकार करना", + "reject": "अस्वीकार करना", + "memberAdded": "यह स्वीकृत है" + }, + "orgUpdate": { + "city": "शहर", + "countryCode": "कंट्री कोड", + "line1": "लाइन 1", + "line2": "लाइन 2", + "postalCode": "डाक कोड", + "dependentLocality": "आश्रित इलाका", + "sortingCode": "कोड क्रमबद्ध करना", + "state": "राज्य/प्रान्त", + "userRegistrationRequired": "उपयोगकर्ता पंजीकरण आवश्यक", + "isVisibleInSearch": "खोज में दृश्यमान", + "enterNameOrganization": "संगठन का नाम दर्ज करें", + "successfulUpdated": "संगठन सफलतापूर्वक अद्यतन किया गया" + }, + "addOnRegister": { + "addNew": "नया जोड़ो", + "addPlugin": "प्लगइन जोड़ें", + "pluginName": "प्लगइन नाम", + "creatorName": "निर्माता का नाम", + "pluginDesc": "प्लगइन विवरण", + "pName": "उदाहरणार्थ: दान", + "cName": "उदाहरण: जॉन डो", + "pDesc": "यह प्लगइन यूआई को सक्षम बनाता है" + }, + "addOnStore": { + "title": "स्टोर पर जोड़ें", + "searchName": "उदाहरणार्थ: दान", + "search": "खोजें", + "enable": "सक्रिय", + "disable": "अक्षम", + "pHeading": "प्लग-इन", + "install": "स्थापित", + "available": "उपलब्ध", + "pMessage": "प्लगइन मौजूद नहीं है" + }, + "addOnEntry": { + "enable": "सक्रिय", + "install": "स्थापित करना", + "uninstall": "स्थापना रद्द करें", + "uninstallMsg": "यह सुविधा अब आपके संगठन से हटा दी गई है", + "installMsg": "यह सुविधा अब आपके संगठन में सक्षम है" + }, + "memberDetail": { + "title": "उपयोगकर्ता विवरण", + "addAdmin": "व्यवस्थापक जोड़ें", + "alreadyIsAdmin": "सदस्य पहले से ही एक व्यवस्थापक है", + "organizations": "संगठनों", + "events": "आयोजन", + "role": "भूमिका", + "createdOn": "पर बनाया", + "main": "मुख्य", + "firstName": "पहला नाम", + "lastName": "उपनाम", + "language": "भाषा", + "gender": "लिंग", + "birthDate": "जन्म तिथि", + "educationGrade": "शैक्षिक ग्रेड", + "employmentStatus": "रोज़गार की स्थिति", + "maritalStatus": "वैवाहिक स्थिति", + "phone": "फ़ोन", + "countryCode": "कंट्री कोड", + "state": "राज्य", + "city": "शहर", + "personalInfoHeading": "व्यक्तिगत जानकारी", + "contactInfoHeading": "संपर्क जानकारी", + "actionsHeading": "कार्रवाई", + "personalDetailsHeading": "प्रोफ़ाइल विवरण", + "appLanguageCode": "भाषा चुनें", + "deleteUser": "उपभोक्ता मिटायें", + "pluginCreationAllowed": "प्लगइन निर्माण की अनुमति दी गई", + "created": "बनाया था", + "adminForOrganizations": "संगठनों के लिए व्यवस्थापक", + "membershipRequests": "सदस्यता अनुरोध", + "adminForEvents": "घटनाओं के लिए व्यवस्थापक", + "addedAsAdmin": "उपयोगकर्ता को व्यवस्थापक के रूप में जोड़ा गया है.", + "userType": "उपयोगकर्ता का प्रकार" + }, + "userLogin": { + "login": "लॉग इन करें", + "loginIntoYourAccount": "अपने खाते में लॉगिन करें", + "invalidDetailsMessage": "कृपया एक वैध ईमेल और पासवर्ड दर्ज करें।", + "notAuthorised": "क्षमा मांगना! ", + "invalidCredentials": "दर्ज किए गए क्रेडेंशियल ग़लत हैं. " + }, + "userRegister": { + "enterFirstName": "अपना पहला नाम दर्ज करें", + "enterLastName": "अपना अंतिम नाम दर्ज करें", + "enterConfirmPassword": "पुष्टि करने के लिए अपना पासवर्ड दर्ज करें", + "alreadyhaveAnAccount": "क्या आपके पास पहले से एक खाता मौजूद है?", + "login": "लॉग इन करें", + "afterRegister": "पंजीकरण सफलतापूर्वक हो गया है। ", + "passwordNotMatch": "पासवर्ड मेल नहीं खाता. ", + "invalidDetailsMessage": "कृपया वैध विवरण दर्ज करें." + }, + "userNavbar": { + "talawa": "तलावा", + "home": "घर", + "people": "लोग", + "events": "आयोजन", + "chat": "बात करना", + "donate": "दान करें", + "language": "भाषा" + }, + "userOrganizations": { + "allOrganizations": "सभी संगठन", + "joinedOrganizations": "संगठनों से जुड़े", + "createdOrganizations": "संगठन बनाये", + "selectOrganization": "एक संगठन चुनें", + "searchUsers": "उपयोगकर्ता खोजें", + "nothingToShow": "यहां दिखाने के लिए कुछ भी नहीं है.", + "organizations": "संगठनों" + }, + "userSidebarOrg": { + "yourOrganizations": "आपके संगठन", + "noOrganizations": "आप अभी तक किसी संगठन में शामिल नहीं हुए हैं.", + "viewAll": "सभी को देखें", + "talawaUserPortal": "तलावा उपयोगकर्ता पोर्टल", + "my organizations": "मेरे संगठन", + "communityProfile": "सामुदायिक प्रोफ़ाइल" + }, + "organizationSidebar": { + "viewAll": "सभी को देखें", + "events": "आयोजन", + "noEvents": "दिखाने के लिए कोई ईवेंट नहीं", + "noMembers": "दिखाने के लिए कोई सदस्य नहीं" + }, + "postCard": { + "likes": "पसंद है", + "comments": "टिप्पणियाँ", + "viewPost": "पोस्ट देखें", + "editPost": "पोस्ट संपादित करें", + "postedOn": "{{date}} को पोस्ट किया गया" + }, + "home": { + "posts": "पदों", + "post": "डाक", + "title": "शीर्षक", + "textArea": "आपके मन में कुछ है?", + "feed": "खिलाना", + "loading": "लोड हो रहा है", + "pinnedPosts": "चिपके पत्र", + "yourFeed": "आपका फ़ीड", + "nothingToShowHere": "यहां दिखाने के लिए कुछ भी नहीं है", + "somethingOnYourMind": "आपके मन में कुछ है?", + "addPost": "पोस्ट जोड़ें", + "startPost": "एक पोस्ट प्रारंभ करें", + "media": "मिडिया", + "event": "आयोजन", + "article": "लेख", + "postNowVisibleInFeed": "पोस्ट अब फीड में दिखाई दे रहा है" + }, + "settings": { + "profileSettings": "पार्श्वचित्र समायोजन", + "gender": "लिंग", + "phoneNumber": "फ़ोन नंबर", + "chooseFile": "फाइलें चुनें", + "birthDate": "जन्म तिथि", + "grade": "शैक्षिक ग्रेड", + "empStatus": "रोज़गार की स्थिति", + "maritalStatus": "वैवाहिक स्थिति", + "state": "शहरी स्थान", + "country": "देश", + "resetChanges": "परिवर्तन रीसेट करें", + "profileDetails": "प्रोफ़ाइल विवरण", + "deleteUserMessage": "डिलीट यूजर बटन पर क्लिक करने से आपका यूजर अपने इवेंट, टैग और सभी संबंधित डेटा के साथ स्थायी रूप से हटा दिया जाएगा।", + "copyLink": "प्रोफ़ाइल लिंक कॉपी करें", + "deleteUser": "उपभोक्ता मिटायें", + "otherSettings": "अन्य सेटिंग", + "changeLanguage": "भाषा बदलें", + "sgender": "लिंग चुनें", + "gradePlaceholder": "ग्रेड दर्ज करें", + "sEmpStatus": "रोजगार की स्थिति चुनें", + "female": "महिला", + "male": "पुरुष", + "employed": "कार्यरत", + "other": "अन्य", + "sMaritalStatus": "वैवाहिक स्थिति चुनें", + "unemployed": "बेरोज़गार", + "married": "विवाहित", + "single": "अकेला", + "widowed": "विधवा", + "divorced": "तलाकशुदा", + "engaged": "काम में लगा हुआ", + "separated": "विभाजित", + "grade1": "ग्रेड 1", + "grade2": "ग्रेड 2", + "grade3": "ग्रेड 3", + "grade4": "ग्रेड 4", + "grade5": "ग्रेड 5", + "grade6": "वर्ग 6", + "grade7": "श्रेणी 7", + "grade8": "कक्षा 8", + "grade9": "श्रेणी 9", + "grade10": "ग्रेड 10", + "grade11": "ग्रेड 11", + "grade12": "कक्षा 12", + "graduate": "स्नातक", + "kg": "किलोग्राम", + "preKg": "पूर्व केजी", + "noGrade": "कोई ग्रेड नहीं", + "fullTime": "पूरा समय", + "partTime": "पार्ट टाईम", + "selectCountry": "कोई देश चुनें", + "enterState": "शहर या राज्य दर्ज करें" + }, + "donate": { + "donations": "दान", + "searchDonations": "दान खोजें", + "donateForThe": "के लिए दान करें", + "amount": "मात्रा", + "yourPreviousDonations": "आपका पिछला दान", + "donate": "दान करें", + "nothingToShow": "यहां दिखाने के लिए कुछ भी नहीं है.", + "success": "दान सफल" + }, + "userEvents": { + "nothingToShow": "यहां दिखाने के लिए कुछ भी नहीं है.", + "createEvent": "कार्यक्रम बनाएँ", + "recurring": "पुनरावर्ती ईवेंट", + "startTime": "समय शुरू", + "endTime": "अंत समय", + "listView": "लिस्ट व्यू", + "calendarView": "कैलेंडर दृश्य", + "allDay": "पूरे दिन", + "eventCreated": "ईवेंट सफलतापूर्वक बनाया और पोस्ट किया गया.", + "eventDetails": "घटना की जानकारी", + "eventTitle": "शीर्षक", + "enterTitle": "शीर्षक दर्ज करें", + "enterDescription": "विवरण दर्ज करें", + "enterLocation": "स्थान दर्ज करें", + "publicEvent": "सार्वजनिक है", + "registerable": "पंजीकरण योग्य है", + "monthlyCalendarView": "मासिक कैलेंडर", + "yearlyCalendarView": "वार्षिक कैलेंडर" + }, + "userEventCard": { + "starts": "प्रारंभ होगा", + "ends": "समाप्त होता है", + "creator": "निर्माता", + "alreadyRegistered": "पहले से ही पंजीकृत" + }, + "advertisement": { + "title": "विज्ञापनों", + "activeAds": "सक्रिय अभियान", + "archievedAds": "पूर्ण अभियान", + "pMessage": "इस अभियान के लिए विज्ञापन मौजूद नहीं हैं.", + "validLink": "लिंक मान्य है", + "invalidLink": "लिंक अमान्य है", + "Rname": "विज्ञापन का नाम दर्ज करें", + "Rtype": "विज्ञापन का प्रकार चुनें", + "Rmedia": "प्रदर्शित करने के लिए मीडिया सामग्री प्रदान करें", + "RstartDate": "आरंभ तिथि चुनें", + "RendDate": "अंतिम तिथि चुनें", + "RClose": "खिड़की बंद करो", + "addNew": "नया विज्ञापन बनाएं", + "EXname": "पूर्व। ", + "EXlink": "पूर्व। ", + "createAdvertisement": "विज्ञापन बनाएं", + "deleteAdvertisement": "विज्ञापन हटाएँ", + "deleteAdvertisementMsg": "क्या आप यह विज्ञापन हटाना चाहते हैं?", + "view": "देखना", + "editAdvertisement": "विज्ञापन संपादित करें", + "advertisementDeleted": "विज्ञापन सफलतापूर्वक हटाया गया।", + "endDateGreaterOrEqual": "समाप्ति तिथि प्रारंभ तिथि से अधिक या उसके बराबर होनी चाहिए", + "advertisementCreated": "विज्ञापन सफलतापूर्वक बनाया गया।" + }, + "userChat": { + "chat": "बात करना", + "contacts": "संपर्क" + }, + "userChatRoom": { + "selectContact": "बातचीत शुरू करने के लिए एक संपर्क चुनें", + "sendMessage": "मेसेज भेजें" + }, + "orgProfileField": { + "loading": "लोड हो रहा है...", + "noCustomField": "कोई कस्टम फ़ील्ड उपलब्ध नहीं है", + "customFieldName": "कार्यक्षेत्र नाम", + "enterCustomFieldName": "फ़ील्ड नाम दर्ज करें", + "customFieldType": "क्षेत्र प्रकार", + "Remove Custom Field": "कस्टम फ़ील्ड हटाएँ", + "fieldSuccessMessage": "फ़ील्ड सफलतापूर्वक जोड़ा गया", + "fieldRemovalSuccess": "फ़ील्ड सफलतापूर्वक हटा दी गई", + "String": "स्ट्रिंग", + "Boolean": "बूलियन", + "Date": "तारीख", + "Number": "संख्या" + }, + "orgActionItemCategories": { + "enableButton": "सक्षम", + "disableButton": "अक्षम करना", + "updateActionItemCategory": "अद्यतन", + "actionItemCategoryName": "नाम", + "actionItemCategoryDetails": "कार्य आइटम श्रेणी विवरण", + "enterName": "नाम दर्ज करें", + "successfulCreation": "कार्रवाई आइटम श्रेणी सफलतापूर्वक बनाई गई", + "successfulUpdation": "कार्रवाई आइटम श्रेणी सफलतापूर्वक अपडेट की गई", + "sameNameConflict": "अपडेट करने के लिए कृपया नाम बदलें", + "categoryEnabled": "कार्य आइटम श्रेणी सक्षम", + "categoryDisabled": "कार्रवाई आइटम श्रेणी अक्षम" + }, + "organizationVenues": { + "title": "स्थानों", + "addVenue": "स्थान जोड़ें", + "venueDetails": "स्थल विवरण", + "venueName": "आयोजन स्थल का नाम", + "enterVenueName": "स्थान का नाम दर्ज करें", + "enterVenueDesc": "स्थान विवरण दर्ज करें", + "capacity": "क्षमता", + "enterVenueCapacity": "स्थान क्षमता दर्ज करें", + "image": "स्थल छवि", + "uploadVenueImage": "स्थल छवि अपलोड करें", + "createVenue": "स्थान बनाएँ", + "venueAdded": "स्थान सफलतापूर्वक जोड़ा गया", + "editVenue": "स्थान अद्यतन करें", + "venueUpdated": "स्थान विवरण सफलतापूर्वक अपडेट किया गया", + "sort": "क्रम से लगाना", + "highestCapacity": "उच्चतम क्षमता", + "lowestCapacity": "सबसे कम क्षमता", + "noVenues": "कोई स्थान नहीं मिला!", + "view": "देखना", + "venueTitleError": "स्थान का शीर्षक खाली नहीं हो सकता!", + "venueCapacityError": "क्षमता एक धनात्मक संख्या होनी चाहिए!", + "searchBy": "खोज से" + }, + "addMember": { + "title": "सदस्य जोड़ें", + "addMembers": "सदस्य जोड़ें", + "existingUser": "मौजूदा उपयोगकर्ता", + "newUser": "नए उपयोगकर्ता", + "searchFullName": "पूरे नाम से खोजें", + "enterFirstName": "प्रथम नाम दर्ज करें", + "enterLastName": "अंतिम नाम दर्ज करो", + "enterConfirmPassword": "पासवर्ड की पुष्टि करें दर्ज करें", + "organization": "संगठन", + "invalidDetailsMessage": "कृपया सभी आवश्यक विवरण प्रदान करें।", + "passwordNotMatch": "सांकेतिक शब्द मेल नहीं खाते।", + "addMember": "सदस्य जोड़ें" + }, + "eventActionItems": { + "title": "एक्शन आइटम्स", + "createActionItem": "एक्शन आइटम बनाएं", + "actionItemCategory": "कार्य आइटम श्रेणी", + "selectActionItemCategory": "एक क्रिया आइटम श्रेणी का चयन करें", + "selectAssignee": "एक समनुदेशिती का चयन करें", + "preCompletionNotes": "टिप्पणियाँ", + "postCompletionNotes": "समापन नोट्स", + "actionItemDetails": "कार्रवाई मद विवरण", + "dueDate": "नियत तारीख", + "completionDate": "पूरा करने की तिथि", + "editActionItem": "क्रिया आइटम संपादित करें", + "deleteActionItem": "क्रिया आइटम हटाएँ", + "deleteActionItemMsg": "क्या आप इस क्रिया आइटम को हटाना चाहते हैं?", + "successfulDeletion": "कार्रवाई आइटम सफलतापूर्वक हटा दिया गया", + "successfulCreation": "कार्रवाई आइटम सफलतापूर्वक बनाया गया", + "successfulUpdation": "कार्रवाई आइटम सफलतापूर्वक अपडेट किया गया", + "notes": "टिप्पणियाँ", + "assignee": "संपत्ति-भागी", + "assigner": "असाइनर", + "assignmentDate": "असाइनमेंट तिथि", + "status": "स्थिति", + "actionItemActive": "सक्रिय", + "actionItemStatus": "कार्रवाई आइटम स्थिति", + "actionItemCompleted": "कार्रवाई आइटम पूर्ण हुआ", + "markCompletion": "पूर्णता को चिह्नित करें", + "save": "बचाना" + }, + "checkIn": { + "errorCheckingIn": "चेक-इन में त्रुटि", + "checkedInSuccessfully": "सफलतापूर्वक चेक-इन किया गया" + }, + "eventRegistrantsModal": { + "errorAddingAttendee": "उपस्थित होने वाले को जोड़ने में त्रुटि", + "errorRemovingAttendee": "उपस्थित होने वाले को हटाने में त्रुटि" + } +} diff --git a/public/locales/sp/common.json b/public/locales/sp/common.json new file mode 100644 index 0000000000..d784652da5 --- /dev/null +++ b/public/locales/sp/common.json @@ -0,0 +1,86 @@ +{ + "firstName": "First Name", + "lastName": "Last Name", + "searchByName": "Search By Name", + "loading": "Loading...", + "endOfResults": "End of results", + "noResultsFoundFor": "No results found for ", + "edit": "Edit", + "admins": "Admins", + "admin": "ADMIN", + "user": "USER", + "superAdmin": "SUPERADMIN", + "members": "Members", + "logout": "Logout", + "login": "Login", + "register": "Register", + "menu": "Menu", + "settings": "Settings", + "users": "Users", + "requests": "Requests", + "OR": "OR", + "cancel": "Cancel", + "close": "Close", + "create": "Create", + "delete": "Delete", + "done": "Done", + "yes": "Yes", + "no": "No", + "filter": "Filter", + "search": "Search", + "description": "Description", + "saveChanges": "Save Changes", + "resetChanges": "Reset Changes", + "displayImage": "Display Image", + "enterEmail": "Enter Email", + "emailAddress": "Email Address", + "email": "Email", + "name": "Name", + "desc": "Description", + "enterPassword": "Enter Password", + "password": "Password", + "confirmPassword": "Confirm Password", + "forgotPassword": "Forgot Password ?", + "talawaAdminPortal": "Talawa Admin Portal", + "address": "Address", + "location": "Location", + "enterLocation": "Enter Location", + "joined": "Joined", + "startDate": "Start Date", + "endDate": "End Date", + "startTime": "Start Time", + "endTime": "End Time", + "My Organizations": "Mis Organizaciones", + "Dashboard": "Tablero", + "People": "Gente", + "Events": "Eventos", + "Venues": "Lugares", + "Action Items": "Elementos de Acción", + "Posts": "Publicaciones", + "Block/Unblock": "Bloquear/Desbloquear", + "Advertisement": "Publicidad", + "Funds": "Fondos", + "Membership Requests": "Solicitudes de Membresía", + "Plugins": "Complementos", + "Plugin Store": "Tienda de Complementos", + "Settings": "Configuraciones", + "createdOn": "Creado En", + "createdBy": "Creado Por", + "usersRole": "Rol del Usuario", + "changeRole": "Cambiar Rol", + "action": "Acción", + "removeUser": "Eliminar Usuario", + "remove": "Eliminar", + "viewProfile": "Ver Perfil", + "profile": "Perfil", + "noFiltersApplied": "No se aplicaron filtros", + "manage": "Administrar", + "searchResultsFor": "Resultados de búsqueda para {{text}}", + "none": "Ninguno", + "sort": "Ordenar", + "Donate": "Donar", + "addedSuccessfully": "{{item}} agregado con éxito", + "updatedSuccessfully": "{{item}} actualizado con éxito", + "removedSuccessfully": "{{item}} eliminado con éxito", + "successfullyUpdated": "Actualizado con éxito" +} diff --git a/public/locales/sp/errors.json b/public/locales/sp/errors.json new file mode 100644 index 0000000000..7d5440637f --- /dev/null +++ b/public/locales/sp/errors.json @@ -0,0 +1,10 @@ +{ + "talawaApiUnavailable": "Talawa-API service is unavailable!. Is it running? Check your network connectivity too.", + "notFound": "Not found", + "unknownError": "An unknown error occurred. Please try again later. {{msg}}", + "notAuthorised": "Sorry! you are not Authorised!", + "errorSendingMail": "Error sending mail", + "emailNotRegistered": "Email not registered", + "notFoundMsg": "Oops! The Page you requested was not found!", + "errorOccurredCouldntCreate": "Ocurrió un error. No se pudo crear {{entity}}" +} diff --git a/public/locales/sp/translation.json b/public/locales/sp/translation.json new file mode 100644 index 0000000000..2d5f46db2b --- /dev/null +++ b/public/locales/sp/translation.json @@ -0,0 +1,1216 @@ +{ + "loginPage": { + "title": "Administrador Talawa", + "fromPalisadoes": "Una aplicación de código abierto de los voluntarios de la Fundación palisados", + "talawa_portal": "Portal De Administración Talawa", + "login": "Acceso", + "userLogin": "Inicio de sesión de usuario", + "register": "Registro", + "firstName": "Primer nombre", + "lastName": "Apellido", + "email": "Correo electrónico", + "password": "Clave", + "atleast_8_char_long": "Al menos 8 caracteres de largo", + "atleast_6_char_long": "Al menos 6 caracteres de largo", + "firstName_invalid": "El nombre debe contener solo letras minúsculas y mayúsculas.", + "lastName_invalid": "El apellido debe contener solo letras minúsculas y mayúsculas.", + "password_invalid": "La contraseña debe contener al menos una letra minúscula, una letra mayúscula, un valor numérico y un carácter especial.", + "email_invalid": "El correo electrónico debe tener al menos 8 caracteres.", + "Password_and_Confirm_password_mismatches.": "Contraseña y Confirmar contraseña no coinciden.", + "confirmPassword": "Confirmar contraseña", + "forgotPassword": "Has olvidado tu contraseña ?", + "enterEmail": "ingrese correo electrónico", + "enterPassword": "introducir la contraseña", + "doNotOwnAnAccount": "¿No tienes una cuenta?", + "talawaApiUnavailable": "El servicio Talawa-API no está disponible. ¿Está funcionando? Verifica también la conectividad de tu red.", + "captchaError": "¡Error de captcha!", + "Please_check_the_captcha": "Por favor, revisa el captcha.", + "Something_went_wrong": "Algo salió mal. Inténtalo después de un tiempo", + "passwordMismatches": "Contraseña y Confirmar contraseña no coinciden.", + "fillCorrectly": "Complete todos los detalles correctamente.", + "notAuthorised": "¡Lo siento! ¡No estás autorizado!", + "notFound": "¡Usuario no encontrado!", + "successfullyRegistered": "Registrado con éxito. Espere hasta que sea aprobado", + "OR": "O", + "admin": "ADMINISTRACIÓN", + "user": "USUARIO", + "lowercase_check": "Al menos una letra mayuscula", + "uppercase_check": "Al menos una letra minúscula", + "numeric_value_check": "Al menos un valor numérico", + "special_char_check": "Al menos un carácter especial", + "loading": "Cargando...", + "selectOrg": "Seleccione una organización", + "afterRegister": "Registro exitoso. Por favor, espere a que el administrador apruebe su solicitud." + }, + "userLoginPage": { + "title": "Administrador Talawa", + "fromPalisadoes": "Una aplicación de código abierto de los voluntarios de la Fundación palisados", + "talawa_portal": "Portal De Administración Talawa", + "login": "Acceso", + "register": "Registro", + "firstName": "Primer nombre", + "lastName": "Apellido", + "email": "Correo electrónico", + "password": "Clave", + "atleast_8_char_long": "Al menos 8 caracteres de largo", + "Password_and_Confirm_password_mismatches.": "Contraseña y Confirmar contraseña no coinciden.", + "confirmPassword": "Confirmar contraseña", + "forgotPassword": "Has olvidado tu contraseña ?", + "enterEmail": "ingrese correo electrónico", + "enterPassword": "introducir la contraseña", + "doNotOwnAnAccount": "¿No tienes una cuenta?", + "talawaApiUnavailable": "El servicio Talawa-API no está disponible. ¿Está funcionando? Verifica también la conectividad de tu red.", + "captchaError": "¡Error de captcha!", + "Please_check_the_captcha": "Por favor, revisa el captcha.", + "Something_went_wrong": "Algo salió mal. Inténtalo después de un tiempo", + "passwordMismatches": "Contraseña y Confirmar contraseña no coinciden.", + "fillCorrectly": "Complete todos los detalles correctamente.", + "notAuthorised": "¡Lo siento! ¡No estás autorizado!", + "notFound": "¡Usuario no encontrado!", + "successfullyRegistered": "Registrado con éxito. Espere hasta que sea aprobado", + "userLogin": "Inicio de sesión de usuario", + "afterRegister": "Registrado exitosamente. Espere a que el administrador apruebe su solicitud.", + "OR": "O", + "loading": "Cargando...", + "selectOrg": "Seleccione una organización" + }, + "latestEvents": { + "eventCardTitle": "Próximos Eventos", + "eventCardSeeAll": "Ver Todos", + "noEvents": "No Hay Eventos Próximos" + }, + "latestPosts": { + "latestPostsTitle": "Últimas Publicaciones", + "seeAllLink": "Ver Todo", + "noPostsCreated": "No se han creado publicaciones" + }, + "listNavbar": { + "talawa_portal": "Portal De Administración Talawa", + "roles": "Roles", + "requests": "Peticiones", + "logout": "Cerrar sesión" + }, + "leftDrawer": { + "talawaAdminPortal": "Portal de administración de Talawa", + "menu": "Menú", + "my organizations": "Mis Organizaciones", + "users": "Usuarios", + "requests": "Solicitudes", + "communityProfile": "Perfil de la comunidad", + "logout": "Cerrar sesión" + }, + "leftDrawerOrg": { + "talawaAdminPortal": "Portal de administración de Talawa", + "menu": "Menú", + "talawa_portal": "Portal De Administración Talawa", + "Dashboard": "Tablero", + "People": "Gente", + "Events": "Eventos", + "Contributions": "Contribuciones", + "Posts": "Publicaciones", + "Block/Unblock": "Bloquear/Desbloquear", + "Plugins": "Complementos", + "Plugin Store": "Tienda de complementos", + "allOrganizations": "Todas las organizaciones", + "yourOrganization": "Tu organización", + "notification": "Notificación", + "settings": "Ajustes", + "language": "Idioma", + "logout": "Cerrar sesión", + "notifications": "Notificaciones", + "spamsThe": "envía correo no deseado", + "group": "grupo", + "noNotifications": "No Notificaciones", + "close": "Cerca" + }, + "orgList": { + "title": "Organizaciones Talawa", + "you": "Tú", + "name": "Nombre", + "designation": "Designacion", + "email": "Correo electrónico", + "searchByName": "Buscar por nombre", + "my organizations": "Mis Organizaciones.", + "createOrganization": "Crear organización", + "createSampleOrganization": "Crear organización de muestra", + "description": "Descripción", + "location": "Ubicación", + "address": "Dirección", + "city": "Ciudad", + "countryCode": "Código de País", + "line1": "Línea 1", + "line2": "Línea 2", + "postalCode": "Código Postal", + "dependentLocality": "Localidad Dependiente", + "sortingCode": "Código de Ordenamiento", + "state": "Estado / Provincia", + "userRegistrationRequired": "Registro de usuario requerido", + "visibleInSearch": "Visible en la búsqueda", + "displayImage": "Mostrar imagen", + "enterName": "Ingrese su nombre", + "sort": "Ordenar", + "Earliest": "Más Temprano", + "Latest": "El último", + "filter": "Filtrar", + "cancel": "Cancelar", + "endOfResults": "Fin de los resultados", + "noOrgErrorTitle": "Organizaciones no encontradas", + "sampleOrgDuplicate": "Solo se permite una organización de muestra", + "noOrgErrorDescription": "Por favor, crea una organización a través del panel de control", + "noResultsFoundFor": "No se encontraron resultados para ", + "OR": "O", + "sampleOrgSuccess": "Organización de ejemplo creada exitosamente" + }, + "orgListCard": { + "admins": "Administradores", + "members": "Miembros", + "manage": "Administrar", + "sampleOrganization": "Organización de muestra" + }, + "paginationList": { + "rowsPerPage": "filas por página", + "all": "Todos" + }, + "requests": { + "title": "Solicitudes", + "sl_no": "Núm.", + "name": "Nombre", + "email": "Correo electrónico", + "accept": "Aceptar", + "reject": "Rechazar", + "searchRequests": "Buscar solicitudes", + "endOfResults": "Fin de los resultados", + "noOrgError": "Organizaciones no encontradas, por favor crea una organización a través del panel", + "noResultsFoundFor": "No se encontraron resultados para ", + "noRequestsFound": "No se encontraron solicitudes", + "acceptedSuccessfully": "Solicitud aceptada exitosamente", + "rejectedSuccessfully": "Solicitud rechazada exitosamente", + "noOrgErrorTitle": "Organizaciones no encontradas", + "noOrgErrorDescription": "Por favor, crea una organización a través del panel de control" + }, + "users": { + "title": "Roles Talawa", + "searchByName": "Buscar por nombre", + "users": "Usuarios", + "name": "Nombre", + "email": "Correo electrónico", + "joined_organizations": "Organizaciones unidas", + "blocked_organizations": "Organizaciones bloqueadas", + "endOfResults": "Fin de los resultados", + "orgJoinedBy": "Organizaciones unidas por", + "orgThatBlocked": "Organizaciones bloqueadas por", + "hasNotJoinedAnyOrg": "No se ha unido a ninguna organización.", + "isNotBlockedByAnyOrg": "No está bloqueado por ninguna organización.", + "searchByOrgName": "Buscar por nombre de organización", + "view": "Ver", + "admin": "ADMINISTRACIÓN", + "superAdmin": "SUPERADMIN", + "user": "USUARIO", + "enterName": "Ingrese su nombre", + "loadingUsers": "Cargando usuarios ...", + "noUserFound": "No se encontró ningún usuario.", + "sort": "Ordenar", + "Oldest": "Más Antiguas Primero", + "Newest": "Más Recientes Primero", + "filter": "Filtrar", + "roleUpdated": "Rol actualizado.", + "noResultsFoundFor": "No se encontraron resultados para ", + "talawaApiUnavailable": "El servicio Talawa-API no está disponible. ¿Está funcionando? Compruebe también la conectividad de su red.", + "cancel": "Cancelar", + "admins": "Administradores", + "members": "Miembros", + "joinNow": "Únete ahora", + "visit": "visita", + "withdraw": "retirar", + "orgJoined": "Unido a la organización exitosamente", + "MembershipRequestSent": "Solicitud de membresía enviada exitosamente", + "AlreadyJoined": "Ya eres miembro de esta organización.", + "errorOccured": "Se produjo un error. Por favor, inténtalo de nuevo más tarde.", + "removeUserFrom": "Eliminar Usuario de {{org}}", + "removeConfirmation": "¿Está seguro de que desea eliminar a '{{name}}' de la organización '{{org}}'?" + }, + "communityProfile": { + "title": "Perfil de la comunidad", + "editProfile": "Editar perfil", + "communityProfileInfo": "Estos detalles aparecerán en la pantalla de inicio de sesión/registro para usted y los miembros de su comunidad.", + "communityName": "Nombre de la comunidad", + "wesiteLink": "Enlace de página web", + "logo": "Logo", + "social": "Enlaces de redes sociales", + "url": "Introducir URL", + "profileChangedMsg": "Se actualizaron correctamente los detalles del perfil.", + "resetData": "Restablezca correctamente los detalles del perfil." + }, + "dashboard": { + "title": "Panel de", + "location": "Ubicación", + "about": "Sobre", + "deleteThisOrganization": "Eliminar esta organización", + "statistics": "Estadísticas", + "members": "Miembros", + "admins": "Administradores", + "posts": "Publicaciones", + "events": "Eventos", + "blockedUsers": "Usuarios bloqueados", + "requests": "Solicitudes", + "viewAll": "Ver Todo", + "upcomingEvents": "Próximos Eventos", + "noUpcomingEvents": "No Hay Próximos Eventos", + "latestPosts": "Últimas Publicaciones", + "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." + }, + "organizationPeople": { + "title": "Miembros Talawa", + "filterByName": "Filtrar por nombre", + "filterByLocation": "Filtrar por Ubicación", + "filterByEvent": "Filtrar por Evento", + "members": "Miembros", + "admins": "Administradores", + "users": "Usuarios", + "searchName": "Ingrese su nombre", + "searchevent": "Ingresar evento", + "searchFirstName": "Ingrese el nombre", + "searchLastName": "Introduzca el apellido", + "people": "Personas", + "sort": "Ordenar por Rol", + "actions": "Acciones", + "existingUser": "Usuario existente", + "newUser": "Nuevo usuario", + "firstName": "Nombre de pila", + "enterFirstName": "Ponga su primer nombre", + "lastName": "Apellido", + "enterLastName": "Ingresa tu apellido", + "emailAddress": "correo electrónico", + "enterEmail": "Ingrese su dirección de correo electrónico", + "password": "Contraseña", + "enterPassword": "Ingresa tu contraseña", + "confirmPassword": "confirmar Contraseña", + "enterConfirmPassword": "Ingrese su contraseña para confirmar", + "organization": "Organización", + "create": "Crear", + "cancel": "Cancelar", + "invalidDetailsMessage": "Ingrese detalles válidos." + }, + "userListCard": { + "joined": "Unido", + "addAdmin": "Agregar administrador", + "addedAsAdmin": "El usuario se agrega como administrador.", + "talawaApiUnavailable": "El servicio Talawa-API no está disponible. ¿Está funcionando? Compruebe también la conectividad de su red." + }, + "orgAdminListCard": { + "joined": "Unido", + "remove": "Remover", + "removeAdmin": "Eliminar administrador", + "removeAdminMsg": "¿Quieres eliminar a este administrador?", + "no": "No", + "yes": "Sí", + "adminRemoved": "Se elimina el administrador.", + "talawaApiUnavailable": "El servicio Talawa-API no está disponible. ¿Está funcionando? Compruebe también la conectividad de su red." + }, + "orgPeopleListCard": { + "joined": "Unido", + "remove": "Remover", + "removeMember": "Eliminar miembro", + "removeMemberMsg": "¿Quieres eliminar a este miembro?", + "no": "No", + "yes": "Sí", + "memberRemoved": "El miembro es eliminado", + "talawaApiUnavailable": "El servicio Talawa-API no está disponible. ¿Está funcionando? Compruebe también la conectividad de su red." + }, + "organizationEvents": { + "title": "Eventos", + "filterByTitle": "Filtrar por Título", + "filterByLocation": "Filtrar por Ubicación", + "filterByDescription": "Filtrar por descripción", + "events": "Eventos", + "addEvent": "Añadir evento", + "eventDetails": "Detalles del evento", + "eventTitle": "Título", + "description": "Descripción", + "location": "Ubicación", + "startDate": "Fecha de inicio", + "endDate": "Fecha final", + "startTime": "Hora de inicio", + "endTime": "Hora de finalización", + "allDay": "Todo el dia", + "recurringEvent": "Evento recurrente", + "isPublic": "Es público", + "isRegistrable": "Es registrable", + "createEvent": "Crear evento", + "enterFilter": "Introducir filtro", + "enterTitle": "Ingrese el título", + "enterDescrip": "Introduce la descripción", + "eventLocation": "Introducir ubicación", + "eventCreated": "¡Felicidades! Se crea el Evento.", + "eventType": "Tipo de evento", + "searchEventName": "Buscar nombre del evento", + "talawaApiUnavailable": "El servicio Talawa-API no está disponible. ¿Está funcionando? Compruebe también la conectividad de su red.", + "customRecurrence": "Recurrencia personalizada", + "repeatsEvery": "Se repite cada", + "repeatsOn": "Se repite en", + "ends": "Finaliza", + "never": "Nunca", + "on": "En", + "after": "Después de", + "occurences": "ocurrencias", + "done": "Hecho" + }, + "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", + "assignee": "Asignado", + "assigner": "Asignador", + "assignmentDate": "Fecha de asignación", + "active": "Activo", + "clearFilters": "Borrar filtros", + "close": "Cerrar", + "completed": "Completado", + "completionDate": "Fecha de finalización", + "createActionItem": "Crear ítem de acción", + "deleteActionItem": "Eliminar ítem de acción", + "deleteActionItemMsg": "¿Desea eliminar este ítem de 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", + "isCompleted": "Completado", + "latest": "Lo más reciente", + "makeActive": "Activar", + "markCompletion": "Marcar finalización", + "no": "No", + "noActionItems": "No hay ítems de acción", + "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", + "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í" + }, + "organizationAgendaCategory": { + "agendaCategoryDetails": "Detalles de la categoría de la agenda", + "updateAgendaCategory": "Actualizar categoría de la agenda", + "title": "Categorías de la agenda", + "name": "Categoría", + "description": "Descripción", + "createdBy": "Creado por", + "options": "Opciones", + "createAgendaCategory": "Crear categoría de la agenda", + "noAgendaCategories": "No hay categorías de la agenda", + "update": "Actualizar", + "agendaCategoryCreated": "Categoría de la agenda creada exitosamente", + "agendaCategoryUpdated": "Categoría de la agenda actualizada exitosamente", + "agendaCategoryDeleted": "Categoría de la agenda eliminada exitosamente", + "deleteAgendaCategory": "Eliminar categoría de la agenda", + "deleteAgendaCategoryMsg": "¿Desea eliminar esta categoría de la agenda?" + }, + "agendaItems": { + "agendaItemDetails": "Detalles del punto del orden del día", + "updateAgendaItem": "Actualizar punto del orden del día", + "title": "Título", + "enterTitle": "Ingresar título", + "sequence": "Secuencia", + "description": "Descripción", + "enterDescription": "Ingresar descripción", + "category": "Categoría del orden del día", + "attachments": "Archivos adjuntos", + "attachmentLimit": "Agregar cualquier archivo de imagen o video hasta 10MB", + "fileSizeExceedsLimit": "El tamaño del archivo excede el límite de 10MB", + "urls": "URLs", + "url": "Agregar enlace a URL", + "enterUrl": "https://example.com", + "invalidUrl": "Ingrese una URL válida", + "link": "Enlace", + "createdBy": "Creado por", + "regular": "Regular", + "note": "Nota", + "duration": "Duración", + "enterDuration": "mm:ss", + "options": "Opciones", + "createAgendaItem": "Crear punto del orden del día", + "noAgendaItems": "No hay puntos del orden del día", + "selectAgendaItemCategory": "Seleccionar una categoría de punto del orden del día", + "update": "Actualizar", + "delete": "Eliminar", + "agendaItemCreated": "Punto del orden del día creado exitosamente", + "agendaItemUpdated": "Punto del orden del día actualizado exitosamente", + "agendaItemDeleted": "Punto del orden del día eliminado exitosamente", + "deleteAgendaItem": "Eliminar punto del orden del día", + "deleteAgendaItemMsg": "¿Desea eliminar este punto del orden del día?" + }, + "eventListCard": { + "location": "Lugar del evento", + "deleteEvent": "Eliminar evento", + "deleteEventMsg": "¿Quieres eliminar este evento?", + "no": "No", + "yes": "Sí", + "editEvent": "Editar evento", + "eventTitle": "Título", + "description": "Descripción", + "startDate": "Fecha de inicio", + "endDate": "Fecha final", + "registerEvent": "Registro", + "alreadyRegistered": "Ya registrado", + "startTime": "Hora de inicio", + "endTime": "Hora de finalización", + "allDay": "Todo el dia", + "recurringEvent": "Evento recurrente", + "isPublic": "Es público", + "isRegistrable": "Es registrable", + "close": "Cerca", + "updatePost": "Actualizar publicación", + "eventDetails": "Detalles del evento", + "eventDeleted": "Evento eliminado con éxito.", + "eventUpdated": "Evento actualizado con éxito.", + "talawaApiUnavailable": "El servicio Talawa-API no está disponible. ¿Está funcionando? Compruebe también la conectividad de su red.", + "thisInstance": "Esta Instancia", + "thisAndFollowingInstances": "Esta y las Siguientes Instancias", + "allInstances": "Todas las Instancias", + "customRecurrence": "Recurrencia personalizada", + "repeatsEvery": "Se repite cada", + "repeatsOn": "Se repite en", + "ends": "Finaliza", + "never": "Nunca", + "on": "En", + "after": "Después de", + "occurences": "ocurrencias", + "done": "Hecho" + }, + "funds": { + "title": "Fondos", + "createFund": "Crear fondo", + "fundName": "Nombre del fondo", + "fundId": "ID de referencia del fondo", + "taxDeductible": "Deducible de impuestos", + "default": "Predeterminado", + "archived": "Archivado", + "fundCreate": "Crear fondo", + "fundUpdate": "Actualizar fondo", + "fundDelete": "Eliminar fondo", + "searchByName": "Buscar por nombre", + "noFundsFound": "No se encontraron fondos", + "createdBy": "Creado por", + "createdOn": "Creado en", + "status": "Estado", + "fundCreated": "Fondo creado correctamente", + "fundUpdated": "Fondo actualizado correctamente", + "fundDeleted": "Fondo eliminado correctamente", + "deleteFundMsg": "¿Está seguro de que desea eliminar este fondo?", + "createdLatest": "Creado más reciente", + "createdEarliest": "Creado más temprano", + "viewCampaigns": "Ver campañas" + }, + "fundCampaign": { + "title": "Campañas de recaudación de fondos", + "campaignName": "Nombre de la campaña", + "campaignOptions": "Opciones", + "fundingGoal": "Meta de financiación", + "addCampaign": "Agregar campaña", + "createdCampaign": "Campaña creada correctamente", + "updatedCampaign": "Campaña actualizada correctamente", + "deletedCampaign": "Campaña eliminada correctamente", + "deleteCampaignMsg": "¿Está seguro de que desea eliminar esta campaña?", + "noCampaigns": "No se encontraron campañas", + "createCampaign": "Crear campaña", + "updateCampaign": "Actualizar campaña", + "deleteCampaign": "Eliminar campaña", + "currency": "Moneda", + "selectCurrency": "Seleccionar moneda", + "searchFullName": "Buscar por nombre", + "viewPledges": "Ver compromisos", + "noCampaignsFound": "No se encontraron campañas", + "latestEndDate": "Fecha de finalización más reciente", + "earliestEndDate": "Fecha de finalización más temprana", + "lowestGoal": "Meta más baja", + "highestGoal": "Meta más alta" + }, + "pledges": { + "title": "Compromisos de Campaña de Financiamiento", + "startDate": "Fecha de Inicio", + "endDate": "Fecha de Finalización", + "pledgeAmount": "Monto del Compromiso", + "pledgeOptions": "Opciones", + "pledgeCreated": "Compromiso creado exitosamente", + "pledgeUpdated": "Compromiso actualizado exitosamente", + "pledgeDeleted": "Compromiso eliminado exitosamente", + "addPledge": "Agregar Compromiso", + "createPledge": "Crear Compromiso", + "currency": "Moneda", + "selectCurrency": "Seleccionar Moneda", + "updatePledge": "Actualizar Compromiso", + "deletePledge": "Eliminar Compromiso", + "amount": "Monto", + "editPledge": "Editar Compromiso", + "deletePledgeMsg": "¿Estás seguro de que quieres eliminar este compromiso?", + "noPledges": "No se encontraron compromisos", + "searchPledger": "Buscar por compromisos", + "highestAmount": "Cantidad más alta", + "lowestAmount": "Cantidad más baja", + "latestEndDate": "Fecha de finalización más reciente", + "earliestEndDate": "Fecha de finalización más cercana", + "campaigns": "Campañas", + "pledges": "Compromisos", + "endsOn": "Finaliza el", + "raisedAmount": "Monto recaudado", + "pledgedAmount": "Monto comprometido" + }, + + "orgPost": { + "title": "Publicaciones de Talawa", + "searchPost": "Buscar Publicación", + "posts": "Publicaciones", + "createPost": "Crear Publicación", + "postDetails": "Detalles de la Publicación", + "postTitle1": "Escribir título de la publicación", + "postTitle": "Título", + "addMedia": "Subir foto o video", + "information": "Información", + "information1": "Escribir información de la publicación", + "addPost": "Agregar Publicación", + "searchTitle": "Buscar por Título", + "searchText": "Buscar por Texto", + "ptitle": "Título de la Publicación", + "postDes": "¿De qué quieres hablar?", + "Title": "Título", + "Text": "Texto", + "cancel": "Cancelar", + "searchBy": "Buscar por", + "Oldest": "Más Antiguas Primero", + "Latest": "Más Recientes Primero", + "sortPost": "Ordenar Publicaciones", + "tag": "Su navegador no admite la etiqueta de video", + "postCreatedSuccess": "¡Felicidades! Has publicado algo.", + "pinPost": "Fijar publicación", + "Next": "Siguiente página", + "Previous": "Página anterior" + }, + "postNotFound": { + "post": "Publicaciones", + "not found!": "Extraviado!", + "organization": "Organización", + "post not found!": "Publicaciones Extraviado!", + "organization not found!": "Organización Extraviado!" + }, + "userNotFound": { + "user": "usuari(a/o)", + "not found!": "extraviado!", + "roles": "papeles", + "user not found!": "usuario no encontrado!", + "member not found!": "Miembro no encontrado!", + "admin not found!": "Administrador no encontrado!", + "roles not found!": "roles no encontrados!" + }, + "orgPostCard": { + "author": "Autor", + "imageURL": "URL de la Imagen", + "videoURL": "URL del Video", + "edit": "Editar Publicación", + "deletePost": "Eliminar Publicación", + "deletePostMsg": "¿Desea eliminar esta publicación?", + "no": "No", + "yes": "Sí", + "editPost": "Editar Publicación", + "postTitle": "Título", + "postTitle1": "Editar título de la publicación", + "information1": "Editar información de la publicación", + "information": "Información", + "image": "Imagen", + "video": "Video", + "close": "Cerrar", + "updatePost": "Actualizar Publicación", + "postDeleted": "Publicación eliminada exitosamente.", + "postUpdated": "Publicación actualizada exitosamente.", + "tag": "Su navegador no admite la etiqueta de video", + "talawaApiUnavailable": "El servicio Talawa-API no está disponible. ¿Está en funcionamiento? Compruebe también su conectividad de red." + }, + "blockUnblockUser": { + "title": "Usuario de bloqueo/desbloqueo de Talawa", + "pageName": "Bloqueo/desbloqueo", + "searchByName": "Buscar por nombre", + "listOfUsers": "Lista de Usuarios que enviaron spam", + "name": "Nombre", + "email": "Correo electrónico", + "block_unblock": "Bloquear/Desbloquear", + "unblock": "Desatascar", + "block": "Bloquear", + "orgName": "Ingrese su nombre", + "blockedSuccessfully": "Usuario bloqueado con éxito", + "Un-BlockedSuccessfully": "Usuario desbloqueado con éxito", + "talawaApiUnavailable": "El servicio Talawa-API no está disponible. ¿Está funcionando? Compruebe también la conectividad de su red.", + "allMembers": "Todos los miembros", + "blockedUsers": "Usuarios bloqueados", + "searchByFirstName": "Buscar por nombre de pila", + "searchByLastName": "Buscar por apellido", + "noResultsFoundFor": "No se encontraron resultados para ", + "noSpammerFound": "No se encontró ningún spammer" + }, + "eventManagement": { + "title": "Gestión de eventos", + "dashboard": "Tablero", + "registrants": "Inscritos", + "eventActions": "Acciones del evento", + "eventAgendas": "Agendas de eventos", + "eventStats": "Estadísticas del evento", + "to": "A" + }, + "forgotPassword": { + "title": "Talawa olvidó su contraseña", + "forgotPassword": "Has olvidado tu contraseña", + "registeredEmail": "Email registrado", + "getOtp": "Obtener OTP", + "enterOtp": "Ingresar OTP", + "enterNewPassword": "Ingrese nueva clave", + "cofirmNewPassword": "Confirmar nueva contraseña", + "changePassword": "Cambia la contraseña", + "backToLogin": "Volver al inicio de sesión", + "userOtp": "por ejemplo 12345", + "password": "Contraseña", + "emailNotRegistered": "El correo electrónico no está registrado.", + "talawaApiUnavailable": "El servicio Talawa-API no está disponible. ¿Está funcionando? Verifica también la conectividad de tu red.", + "errorSendingMail": "Error al enviar correo.", + "passwordMismatches": "Contraseña y Confirmar contraseña no coinciden.", + "passwordChanges": "La contraseña cambia correctamente.", + "OTPsent": "OTP se envía a su correo electrónico registrado" + }, + "pageNotFound": { + "title": "404 No encontrado", + "talawaAdmin": "Administrador de Talawa", + "talawaUser": "Usuario de Talawa", + "404": "404", + "notFoundMsg": "¡Ups! ¡No se encontró la página que solicitaste!", + "backToHome": "De vuelta a casa" + }, + "orgContribution": { + "title": "Contribuciones Talawa", + "filterByName": "Filtrar por nombre", + "filterByTransId": "Filtrar por ID de transacción", + "recentStats": "Estadísticas recientes", + "contribution": "Contribución", + "orgname": "Ingrese su nombre", + "searchtransaction": "Ingrese la identificación de la transacción" + }, + "contriStats": { + "recentContribution": "Contribución reciente", + "highestContribution": "Contribución más alta", + "totalContribution": "Contribución total" + }, + "orgContriCards": { + "date": "Fecha", + "transactionId": "ID de transacción", + "amount": "Monto" + }, + "orgSettings": { + "title": "Configuración Talawa", + "pageName": "Configuración", + "general": "General", + "actionItemCategories": "Categorías de elementos de acción", + "updateYourDetails": "Actualiza tus datos", + "updateYourPassword": "Actualice su contraseña", + "updateOrganization": "Actualizar Organización", + "seeRequest": "Ver Solicitud", + "settings": "Ajustes", + "noData": "Sin datos", + "otherSettings": "Otras Configuraciones", + "changeLanguage": "Cambiar Idioma", + "manageCustomFields": "Gestionar Campos Personalizados" + }, + "deleteOrg": { + "deleteOrganization": "Eliminar organización", + "deleteSampleOrganization": "Eliminar organización de muestra", + "deleteMsg": "¿Desea eliminar esta organización?", + "cancel": "Cancelar", + "confirmDelete": "Confirmar eliminación", + "longDelOrgMsg": "Al hacer clic en el botón Eliminar organización, la organización se eliminará permanentemente junto con sus eventos, etiquetas y todos los datos relacionados.", + "successfullyDeletedSampleOrganization": "Organización de muestra eliminada correctamente" + }, + "userUpdate": { + "firstName": "Primer nombre", + "lastName": "Apellido", + "email": "Correo electrónico", + "password": "Clave", + "appLanguageCode": "Idioma predeterminado", + "userType": "Tipo de usuario", + "admin": "Administración", + "superAdmin": "Superadministrador", + "displayImage": "Mostrar imagen", + "saveChanges": "Guardar cambios", + "cancel": "Cancelar" + }, + "userPasswordUpdate": { + "previousPassword": "Contraseña anterior", + "newPassword": "Nueva contraseña", + "confirmNewPassword": "Confirmar nueva contraseña", + "saveChanges": "Guardar cambios", + "cancel": "Cancelar", + "passCantBeEmpty": "La contraseña no puede estar vacía", + "passNoMatch": "La nueva contraseña y la confirmación no coinciden." + }, + "orgDelete": { + "deleteOrg": "Eliminar organización" + }, + "membershipRequest": { + "joined": "Unido", + "accept": "Aceptar", + "reject": "Rechazar", + "memberAdded": "es aceptado", + "talawaApiUnavailable": "El servicio Talawa-API no está disponible. ¿Está funcionando? Compruebe también la conectividad de su red." + }, + "orgUpdate": { + "name": "Nombre", + "description": "Descripción", + "location": "ubicación", + "address": "Dirección", + "city": "Ciudad", + "countryCode": "Código de País", + "line1": "Línea 1", + "line2": "Línea 2", + "postalCode": "Código Postal", + "dependentLocality": "Localidad Dependiente", + "sortingCode": "Código de Ordenamiento", + "state": "Estado / Provincia", + "displayImage": "Mostrar imagen", + "userRegistrationRequired": "Registro de usuario requerido", + "isVisibleInSearch": "Visible en la búsqueda", + "saveChanges": "Guardar cambios", + "cancel": "Cancelar", + "enterNameOrganization": "Ingrese el nombre de la organización", + "successfulUpdated": "Exitoso actualizado", + "talawaApiUnavailable": "El servicio Talawa-API no está disponible. ¿Está funcionando? Compruebe también la conectividad de su red." + }, + "addOnRegister": { + "addNew": "Agregar nueva", + "addPlugin": "Agregar complemento", + "pluginName": "Nombre del complemento", + "creatorName": "Nombre del creadora", + "pluginDesc": "Descripción del complemento", + "close": "Cerca", + "register": "Registro", + "pName": "Ej: Donaciones", + "cName": "Ej: John Doe", + "pDesc": "Este complemento habilita la interfaz de usuario para" + }, + "addOnStore": { + "title": "Tienda de complementos", + "searchName": "Ej: Donaciones", + "search": "Buscar", + "enable": "Activada", + "disable": "Desactivada", + "pHeading": "Complementos", + "install": "Instalada", + "available": "Disponible", + "pMessage": "El complemento no existe", + "filter": "filtros" + }, + "addOnEntry": { + "enable": "Activada", + "install": "Instalar", + "uninstall": "Desinstalar" + }, + "memberDetail": { + "title": "Detalles del usuario", + "addAdmin": "Agregar administrador", + "alreadyIsAdmin": "El Miembro ya es Administrador", + "organizations": "Organizaciones", + "events": "Eventos", + "role": "Rol", + "email": "Correo electrónico", + "createdOn": "Creado en", + "main": "Principal", + "firstName": "Nombre", + "lastName": "Apellido", + "language": "Idioma", + "gender": "Género", + "birthDate": "Fecha de Nacimiento", + "educationGrade": "Nivel Educativo", + "employmentStatus": "Estado Laboral", + "maritalStatus": "Estado Civil", + "displayImage": "Imagen de Perfil", + "phone": "Teléfono", + "address": "Dirección", + "countryCode": "Código de País", + "state": "Estado", + "city": "Ciudad", + "personalInfoHeading": "Información Personal", + "contactInfoHeading": "Información de Contacto", + "actionsHeading": "Acciones", + "personalDetailsHeading": "Detalles del perfil", + "appLanguageCode": "Elegir Idioma", + "delete": "Eliminar Usuario", + "saveChanges": "Guardar Cambios", + "pluginCreationAllowed": "Permitir creación de complementos", + "joined": "Unido", + "created": "Creado", + "adminForOrganizations": "Administrador de organizaciones", + "membershipRequests": "Solicitudes de membresía", + "adminForEvents": "Administrador de eventos", + "addedAsAdmin": "El usuario se agrega como administrador.", + "talawaApiUnavailable": "El servicio Talawa-API no está disponible. Compruebe amablemente su conexión de red y espere un momento." + }, + "userLogin": { + "login": "Acceso", + "forgotPassword": "Has olvidado tu contraseña ?", + "loginIntoYourAccount": "Inicie sesión en su cuenta", + "emailAddress": "correo electrónico", + "enterEmail": "Ingrese su dirección de correo electrónico", + "password": "Contraseña", + "enterPassword": "Ingresa tu contraseña", + "register": "Registro", + "invalidDetailsMessage": "Por favor, introduzca un correo electrónico y una contraseña válidos.", + "notAuthorised": "¡Lo siento! usted no está autorizado!", + "invalidCredentials": "Las credenciales ingresadas son incorrectas. Ingrese credenciales válidas.", + "talawaApiUnavailable": "El servicio Talawa-API no está disponible. Compruebe amablemente su conexión de red y espere un momento." + }, + "userRegister": { + "register": "Registro", + "firstName": "Nombre de pila", + "enterFirstName": "Ponga su primer nombre", + "lastName": "Apellido", + "enterLastName": "Ingresa tu apellido", + "emailAddress": "correo electrónico", + "enterEmail": "Ingrese su dirección de correo electrónico", + "password": "Contraseña", + "enterPassword": "Ingresa tu contraseña", + "confirmPassword": "confirmar Contraseña", + "enterConfirmPassword": "Ingrese su contraseña para confirmar", + "alreadyhaveAnAccount": "¿Ya tienes una cuenta?", + "login": "Acceso", + "afterRegister": "Registrado exitosamente. Espere a que el administrador apruebe su solicitud.", + "passwordNotMatch": "La contraseña no coincide. Confirme la contraseña y vuelva a intentarlo.", + "invalidDetailsMessage": "Ingrese detalles válidos.", + "talawaApiUnavailable": "El servicio Talawa-API no está disponible. Compruebe amablemente su conexión de red y espere un momento." + }, + "userNavbar": { + "talawa": "Talawa", + "home": "Hogar", + "people": "Gente", + "events": "Eventos", + "chat": "Charlar", + "donate": "Donar", + "settings": "Ajustes", + "language": "Idioma", + "logout": "Cerrar sesión", + "close": "Cerca" + }, + "userOrganizations": { + "allOrganizations": "Todas las organizaciones", + "joinedOrganizations": "Organizaciones unidas", + "createdOrganizations": "Organizaciones creadas", + "search": "Buscar usuarios", + "nothingToShow": "Nada que mostrar aquí.", + "selectOrganization": "Seleccionar organización", + "filter": "Filtrar", + "organizations": "Organizaciones", + "searchByName": "Buscar por nombre" + }, + "userSidebarOrg": { + "yourOrganizations": "Tus Organizaciones", + "noOrganizations": "Aún no te has unido a ninguna organización.", + "viewAll": "Ver todo", + "talawaUserPortal": "Talawa portal de usuario", + "menu": "Menú", + "my organizations": "Mis Organizaciones.", + "users": "Usuarios", + "requests": "Solicitudes", + "communityProfile": "Perfil de la comunidad", + "logout": "Cerrar sesión", + "settings": "Ajustes" + }, + "organizationSidebar": { + "viewAll": "Ver todo", + "events": "Eventos", + "members": "Miembros", + "noEvents": "No hay eventos para mostrar", + "noMembers": "No hay miembros para mostrar" + }, + "postCard": { + "likes": "Gustos", + "comments": "Comentarios", + "viewPost": "Ver publicación", + "editPost": "Editar publicación", + "postedOn": "Publicado el {{date}}" + }, + "home": { + "feed": "Alimentar", + "pinnedPosts": "Ver publicaciones fijadas", + "somethingOnYourMind": "¿Algo en tu mente?", + "addPost": "Agregar publicación", + "startPost": "Comenzar una publicación", + "media": "Medios", + "event": "Evento", + "article": "Artículo", + "postNowVisibleInFeed": "La publicación ahora es visible en el feed" + }, + "settings": { + "settings": "Ajustes", + "profileSettings": "Configuración de perfil", + "firstName": "Nombre de pila", + "lastName": "Apellido", + "gender": "Género", + "emailAddress": "Dirección de correo electrónico", + "phoneNumber": "Número de teléfono", + "displayImage": "Imagen de perfil", + "chooseFile": "Elegir archivo", + "birthDate": "Fecha de nacimiento", + "grade": "Nivel educativo", + "empStatus": "Situación laboral", + "maritalStatus": "Estado civil", + "address": "Dirección", + "state": "Ciudad/Estado", + "country": "País", + "resetChanges": "Restablecer cambios", + "saveChanges": "Guardar cambios", + "profileDetails": "Detalles del perfil", + "deleteUserMessage": "Al hacer clic en el botón Eliminar usuario, su usuario se eliminará permanentemente junto con sus eventos, etiquetas y todos los datos relacionados.", + "copyLink": "Copiar enlace del perfil", + "deleteUser": "Eliminar usuario", + "otherSettings": "Otras configuraciones", + "changeLanguage": "Cambiar idioma", + "sgender": "Seleccionar género", + "gradePlaceholder": "Ingresar grado", + "sEmpStatus": "Seleccionar estado de empleo", + "male": "Masculino", + "female": "Femenino", + "other": "Otro", + "employed": "Empleado", + "unemployed": "Desempleado", + "sMaritalStatus": "Seleccionar estado civil", + "single": "Soltero", + "married": "Casado", + "divorced": "Divorciado", + "widowed": "Viudo", + "engaged": "Comprometido", + "separated": "Separado", + "grade1": "1er Grado", + "grade2": "2do Grado", + "grade3": "3er Grado", + "grade4": "4to Grado", + "grade5": "5to Grado", + "grade6": "6to Grado", + "grade7": "7mo Grado", + "grade8": "8vo Grado", + "grade9": "9no Grado", + "grade10": "10mo Grado", + "grade11": "11vo Grado", + "grade12": "12vo Grado", + "graduate": "Graduado", + "kg": "KG", + "preKg": "Pre-KG", + "noGrade": "Sin Grado", + "fullTime": "Tiempo Completo", + "partTime": "Medio Tiempo", + "enterState": "Ingresar ciudad o estado", + "selectCountry": "Seleccionar un país", + "joined": "Unido" + }, + "donate": { + "donations": "Donaciones", + "searchDonations": "Buscar donaciones", + "donateForThe": "Donar para el", + "donateTo": "Donar a", + "amount": "Cantidad", + "yourPreviousDonations": "Tus donaciones anteriores", + "donate": "Donar", + "nothingToShow": "Nada que mostrar aquí.", + "success": "Donación exitosa" + }, + "userEvents": { + "nothingToShow": "No hay nada que mostrar aquí.", + "search": "Buscar", + "createEvent": "Crear evento", + "recurring": "Periódica", + "startTime": "Hora de inicio", + "endTime": "Hora de finalización", + "cancel": "Cancelar", + "create": "Crear", + "listView": "Vista de la lista", + "calendarView": "Vista de calendario", + "allDay": "Todo el dia", + "eventCreated": "Evento creado y publicado exitosamente.", + "eventDetails": "Detalles del evento", + "eventTitle": "Título", + "enterTitle": "Ingrese el título", + "eventDescription": "Descripción", + "enterDescription": "Ingresar descripción", + "eventLocation": "Ubicación", + "enterLocation": "Ingresar Ubicación", + "startDate": "Fecha de inicio", + "endDate": "Fecha de finalización", + "publicEvent": "Es público", + "registerable": "Es registrable", + "monthlyCalendarView": "Calendario mensual", + "yearlyCalendarView": "Calendario anual" + }, + "userEventCard": { + "location": "Ubicación", + "starts": "Empieza", + "ends": "Termina", + "creator": "Creadora", + "alreadyRegistered": "Ya registrado", + "register": "Registro" + }, + "advertisement": { + "title": "Anuncios", + "pHeading": "Gestionar anuncios", + "activeAds": "Campañas activas", + "archievedAds": "Campañas completadas", + "pMessage": "No hay anuncios disponibles para esta campaña.", + "delete": "Eliminar", + "validLink": "El enlace es válido.", + "invalidLink": "El enlace no es válido.", + "close": "Cerrar", + "deleteAdvertisement": "Eliminar anuncio", + "deleteAdvertisementMsg": "¿Desea eliminar este anuncio?", + "no": "No", + "yes": "Sí", + "Rmedia": "Proporcionar contenido multimedia para mostrar", + "view": "Ver", + "edit": "Editar", + "editAdvertisement": "Editar Anuncio", + "advertisementDeleted": "Anuncio eliminado con éxito.", + "endDateGreaterOrEqual": "La fecha de finalización debe ser mayor o igual a la fecha de inicio", + "advertisementCreated": "Anuncio creado con éxito.", + "saveChanges": "Guardar Cambios", + "endOfResults": "Fin de los resultados" + }, + "userChat": { + "chat": "Charlar", + "search": "Buscar", + "contacts": "Contactos" + }, + "userChatRoom": { + "selectContact": "Seleccione un contacto para iniciar una conversación", + "sendMessage": "Enviar mensaje" + }, + "orgProfileField": { + "loading": "Cargando..", + "noCustomField": "No hay campos personalizados disponibles", + "customFieldName": "Nombre del Campo", + "enterCustomFieldName": "Ingrese el Nombre del Campo", + "customFieldType": "Tipo de Campo", + "saveChanges": "Guardar Cambios", + "Remove Custom Field": "Eliminar Campo Personalizado", + "fieldSuccessMessage": "Campo añadido exitosamente", + "fieldRemovalSuccess": "Campo eliminado exitosamente", + "String": "Cadena", + "Boolean": "Booleano", + "Date": "Fecha", + "Number": "Número" + }, + "orgActionItemCategories": { + "createButton": "Crear", + "editButton": "Editar", + "enableButton": "Habilitar", + "disableButton": "Inhabilitar", + "updateActionItemCategory": "Actualizar", + "actionItemCategoryName": "Nombre", + "actionItemCategoryDetails": "Detalles de la categoría de elemento de acción", + "enterName": "Introduzca el nombre", + "successfulCreation": "Categoría de elemento de acción creada correctamente", + "successfulUpdation": "Categoría de elemento de acción actualizada correctamente", + "sameNameConflict": "Cambie el nombre para realizar una actualización", + "categoryEnabled": "Categoría de elemento de acción habilitada", + "categoryDisabled": "Categoría de elemento de acción deshabilitada" + }, + "organizationVenues": { + "title": "Lugares", + "addVenue": "Agregar lugar", + "venueDetails": "Detalles del lugar", + "venueName": "Nombre del lugar", + "enterVenueName": "Ingrese el nombre del lugar", + "description": "Descripción del lugar", + "enterVenueDesc": "Ingrese la descripción del lugar", + "capacity": "Capacidad", + "enterVenueCapacity": "Ingrese la capacidad del lugar", + "image": "Imagen del lugar", + "uploadVenueImage": "Subir imagen del lugar", + "createVenue": "Crear lugar", + "venueAdded": "Lugar agregado correctamente", + "editVenue": "Actualizar lugar", + "venueUpdated": "Detalles del lugar actualizados correctamente", + "sort": "Ordenar", + "highestCapacity": "Mayor capacidad", + "lowestCapacity": "Menor capacidad", + "noVenues": "¡No se encontraron lugares!", + "edit": "Editar", + "view": "Ver", + "delete": "Eliminar", + "venueTitleError": "¡El título del lugar no puede estar vacío!", + "venueCapacityError": "¡La capacidad debe ser un número positivo!", + "searchBy": "Buscar por", + "name": "Nombre", + "desc": "Descripción" + }, + "addMember": { + "title": "Agregar miembro", + "addMembers": "Agregar miembros", + "existingUser": "Usuario existente", + "newUser": "Usuario nuevo", + "searchFullName": "Buscar por nombre completo", + "firstName": "Nombre", + "enterFirstName": "Ingrese el nombre", + "lastName": "Apellido", + "enterLastName": "Ingrese el apellido", + "emailAddress": "Dirección de correo electrónico", + "enterEmail": "Ingrese el correo electrónico", + "password": "Contraseña", + "enterPassword": "Ingrese la contraseña", + "confirmPassword": "Confirmar contraseña", + "enterConfirmPassword": "Ingrese la contraseña de confirmación", + "organization": "Organización", + "cancel": "Cancelar", + "create": "Crear", + "invalidDetailsMessage": "Por favor proporcione todos los detalles requeridos.", + "passwordNotMatch": "Las contraseñas no coinciden.", + "user": "Usuario", + "addMember": "Agregar miembro" + }, + "eventActionItems": { + "title": "Elementos de acción", + "createActionItem": "Crear elementos de acción", + "actionItemCategory": "Categoría de elemento de acción", + "selectActionItemCategory": "Seleccione una categoría de elemento de acción", + "selectAssignee": "Seleccione un asignado", + "preCompletionNotes": "Notas", + "postCompletionNotes": "Notas finales", + "actionItemDetails": "Detalles del elemento de acción", + "dueDate": "Fecha de vencimiento", + "completionDate": "Fecha de finalización", + "editActionItem": "Editar elemento de acción", + "deleteActionItem": "Eliminar elemento de acción", + "deleteActionItemMsg": "¿Quieres eliminar este elemento de acción?", + "yes": "Sí", + "no": "no", + "successfulDeletion": "Elemento de acción eliminado exitosamente", + "successfulCreation": "Elemento de acción creado exitosamente", + "successfulUpdation": "Elemento de acción actualizado correctamente", + "notes": "Notas", + "assignee": "Cesionario", + "assigner": "Asignador", + "assignmentDate": "Fecha de asignación", + "status": "Estado", + "actionItemActive": "Activo", + "actionItemStatus": "Estado del elemento de acción", + "actionItemCompleted": "Elemento de acción completado", + "markCompletion": "Marcar finalización", + "save": "Guardar" + }, + "checkIn": { + "errorCheckingIn": "Error al registrarse", + "checkedInSuccessfully": "Registrado con éxito" + }, + "eventRegistrantsModal": { + "errorAddingAttendee": "Error al agregar asistente", + "errorRemovingAttendee": "Error al eliminar asistente" + } +} diff --git a/public/locales/zh/common.json b/public/locales/zh/common.json new file mode 100644 index 0000000000..71b697b354 --- /dev/null +++ b/public/locales/zh/common.json @@ -0,0 +1,86 @@ +{ + "firstName": "名", + "lastName": "姓", + "searchByName": "按名称搜索", + "loading": "加载中...", + "endOfResults": "结果结束", + "noResultsFoundFor": "没有找到结果 ", + "edit": "编辑", + "admins": "管理员", + "admin": "行政", + "user": "用户", + "superAdmin": "超级管理员", + "members": "会员", + "logout": "登出", + "login": "登录", + "register": "登记", + "menu": "菜单", + "settings": "设置", + "users": "用户", + "requests": "要求", + "OR": "或者", + "cancel": "取消", + "close": "关闭", + "create": "创造", + "delete": "删除", + "done": "完毕", + "yes": "是的", + "no": "不", + "filter": "筛选", + "search": "搜索", + "description": "描述", + "saveChanges": "保存更改", + "resetChanges": "重置更改", + "displayImage": "显示图像", + "enterEmail": "输入电子邮件", + "emailAddress": "电子邮件地址", + "email": "电子邮件", + "name": "姓名", + "desc": "描述", + "enterPassword": "输入密码", + "password": "密码", + "confirmPassword": "确认密码", + "forgotPassword": "忘记密码 ?", + "talawaAdminPortal": "塔拉瓦管理门户", + "address": "地址", + "location": "地点", + "enterLocation": "输入位置", + "joined": "已加入", + "startDate": "开始日期", + "endDate": "结束日期", + "startTime": "开始时间", + "endTime": "时间结束", + "My Organizations": "我的组织", + "Dashboard": "仪表板", + "People": "人们", + "Events": "事件", + "Venues": "场地", + "Action Items": "行动项目", + "Posts": "帖子", + "Block/Unblock": "封锁/解除封锁", + "Advertisement": "广告", + "Funds": "资金", + "Membership Requests": "会员请求", + "Plugins": "插件", + "Plugin Store": "插件商店", + "Settings": "设置", + "createdOn": "创建于", + "createdBy": "创建者", + "usersRole": "用户角色", + "changeRole": "更改角色", + "action": "操作", + "removeUser": "删除用户", + "remove": "删除", + "viewProfile": "查看个人资料", + "profile": "轮廓", + "noFiltersApplied": "未应用筛选器", + "manage": "管理", + "searchResultsFor": "搜索结果", + "none": "没有", + "sort": "种类", + "Donate": "捐赠", + "addedSuccessfully": "{{item}} 添加成功", + "updatedSuccessfully": "{{item}} 更新成功", + "removedSuccessfully": "{{item}} 删除成功", + "successfullyUpdated": "更新成功" +} diff --git a/public/locales/zh/errors.json b/public/locales/zh/errors.json new file mode 100644 index 0000000000..1466985403 --- /dev/null +++ b/public/locales/zh/errors.json @@ -0,0 +1,10 @@ +{ + "talawaApiUnavailable": "Talawa-API 服务不可用!", + "notFound": "未找到", + "unknownError": "出现未知错误。 {{msg}}", + "notAuthorised": "对不起!", + "errorSendingMail": "发送邮件时出错", + "emailNotRegistered": "邮箱未注册", + "notFoundMsg": "哎呀!", + "errorOccurredCouldntCreate": "发生错误。 无法创建{{entity}}" +} diff --git a/public/locales/zh/translation.json b/public/locales/zh/translation.json new file mode 100644 index 0000000000..6f8cf9e278 --- /dev/null +++ b/public/locales/zh/translation.json @@ -0,0 +1,984 @@ +{ + "loginPage": { + "title": "塔拉瓦管理员", + "fromPalisadoes": "Palisadoes 基金会志愿者开发的开源应用程序", + "userLogin": "用户登录", + "atleast_8_char_long": "至少 8 个字符长", + "atleast_6_char_long": "至少 6 个字符长", + "firstName_invalid": "名字只能包含小写和大写字母", + "lastName_invalid": "姓氏只能包含小写和大写字母", + "password_invalid": "密码应至少包含1个小写字母、1个大写字母、1个数字和1个特殊字符", + "email_invalid": "电子邮件应至少包含 8 个字符", + "Password_and_Confirm_password_mismatches.": "密码和确认密码不匹配。", + "doNotOwnAnAccount": "没有帐户?", + "captchaError": "验证码错误!", + "Please_check_the_captcha": "请检查验证码。", + "Something_went_wrong": "出了点问题,请稍后再试。", + "passwordMismatches": "密码和确认密码不匹配。", + "fillCorrectly": "正确填写所有详细信息。", + "successfullyRegistered": "注册成功。", + "lowercase_check": "至少一个小写字母", + "uppercase_check": "至少有一个大写字母", + "numeric_value_check": "至少设定一个数值", + "special_char_check": "至少一个特殊字符", + "selectOrg": "选择一个组织", + "afterRegister": "注册成功。" + }, + "userLoginPage": { + "title": "塔拉瓦管理员", + "fromPalisadoes": "Palisadoes 基金会志愿者开发的开源应用程序", + "atleast_8_char_long": "至少 8 个字符长", + "Password_and_Confirm_password_mismatches.": "密码和确认密码不匹配。", + "doNotOwnAnAccount": "没有帐户?", + "captchaError": "验证码错误!", + "Please_check_the_captcha": "请检查验证码。", + "Something_went_wrong": "出了点问题,请稍后再试。", + "passwordMismatches": "密码和确认密码不匹配。", + "fillCorrectly": "正确填写所有详细信息。", + "successfullyRegistered": "注册成功。", + "userLogin": "用户登录", + "afterRegister": "注册成功。", + "selectOrg": "选择一个组织" + }, + "latestEvents": { + "eventCardTitle": "即将举行的活动", + "eventCardSeeAll": "查看全部", + "noEvents": "没有即将举行的活动" + }, + "latestPosts": { + "latestPostsTitle": "最新帖子", + "seeAllLink": "查看全部", + "noPostsCreated": "没有创建帖子" + }, + "listNavbar": { + "roles": "角色" + }, + "leftDrawer": { + "my organizations": "我的组织", + "requests": "会员申请", + "communityProfile": "社区简介" + }, + "leftDrawerOrg": { + "Dashboard": "仪表板", + "People": "人们", + "Events": "活动", + "Contributions": "贡献", + "Posts": "帖子", + "Block/Unblock": "阻止/解除阻止", + "Plugins": "插件", + "Plugin Store": "插件商店", + "Advertisement": "广告", + "allOrganizations": "所有组织", + "yourOrganization": "您的组织", + "notification": "通知", + "language": "语言", + "notifications": "通知", + "spamsThe": "垃圾邮件", + "group": "团体", + "noNotifications": "无通知" + }, + "orgList": { + "title": "塔拉瓦组织", + "you": "你", + "designation": "指定", + "my organizations": "我的组织", + "createOrganization": "创建组织", + "createSampleOrganization": "创建样本组织", + "city": "城市", + "countryCode": "国家代码", + "dependentLocality": "附属地点", + "line1": "1号线", + "line2": "2号线", + "postalCode": "邮政编码", + "sortingCode": "排序代码", + "state": "州/省", + "userRegistrationRequired": "需要用户注册", + "visibleInSearch": "在搜索中可见", + "enterName": "输入名字", + "sort": "种类", + "Latest": "最新的", + "Earliest": "最早", + "noOrgErrorTitle": "未找到组织", + "sampleOrgDuplicate": "只允许一个样本组织", + "noOrgErrorDescription": "请通过仪表板创建组织", + "manageFeatures": "管理功能", + "manageFeaturesInfo": "创建成功!", + "goToStore": "前往插件商店", + "enableEverything": "启用一切", + "sampleOrgSuccess": "样本组织已成功创建" + }, + "orgListCard": { + "manage": "管理", + "sampleOrganization": "组织样本" + }, + "paginationList": { + "rowsPerPage": "每页行数", + "all": "全部" + }, + "requests": { + "title": "会员申请", + "sl_no": "SL。", + "accept": "接受", + "reject": "拒绝", + "searchRequests": "搜索会员请求", + "noOrgError": "未找到组织,请通过仪表板创建组织", + "noRequestsFound": "未找到会员申请", + "acceptedSuccessfully": "请求已成功接受", + "rejectedSuccessfully": "请求被成功拒绝", + "noOrgErrorTitle": "未找到组织", + "noOrgErrorDescription": "请通过仪表板创建组织" + }, + "users": { + "title": "塔拉瓦角色", + "joined_organizations": "加入组织", + "blocked_organizations": "被阻止的组织", + "orgJoinedBy": "加入组织", + "orgThatBlocked": "阻止的组织", + "hasNotJoinedAnyOrg": "没有加入任何组织", + "isNotBlockedByAnyOrg": "没有被任何组织封锁", + "searchByOrgName": "按组织名称搜索", + "view": "看法", + "enterName": "输入名字", + "loadingUsers": "正在加载用户...", + "noUserFound": "未找到用户", + "sort": "种类", + "Newest": "新的先来", + "Oldest": "最旧的在前", + "noOrgError": "未找到组织,请通过仪表板创建组织", + "roleUpdated": "角色已更新。", + "joinNow": "立即加入", + "visit": "访问", + "withdraw": "拉幅", + "removeUserFrom": "从{{org}}中删除用户", + "removeConfirmation": "您确定要将'{{name}}'从组织'{{org}}'中删除吗?" + }, + "communityProfile": { + "title": "社区简介", + "editProfile": "编辑个人资料", + "communityProfileInfo": "这些详细信息将显示在您和您的社区成员的登录/注册屏幕上", + "communityName": "社区名字", + "wesiteLink": "网站链接", + "logo": "标识", + "social": "社交媒体链接", + "url": "输入网址", + "profileChangedMsg": "已成功更新个人资料详细信息。", + "resetData": "成功重置个人资料详细信息。" + }, + "dashboard": { + "title": "仪表板", + "about": "关于", + "deleteThisOrganization": "删除该组织", + "statistics": "统计数据", + "posts": "帖子", + "events": "活动", + "blockedUsers": "被阻止的用户", + "viewAll": "查看全部", + "upcomingEvents": "即将举行的活动", + "noUpcomingEvents": "没有即将举行的活动", + "latestPosts": "最新帖子", + "noPostsPresent": "没有帖子", + "membershipRequests": "会员请求", + "noMembershipRequests": "没有会员请求" + }, + "organizationPeople": { + "title": "塔拉瓦会员", + "filterByName": "按名称过滤", + "filterByLocation": "按地点过滤", + "filterByEvent": "按事件过滤", + "searchName": "输入名字", + "searchevent": "输入事件", + "searchFullName": "输入全名", + "people": "人们", + "sort": "按角色搜索", + "actions": "行动", + "addMembers": "添加会员", + "existingUser": "现有用户", + "newUser": "新用户", + "enterFirstName": "输入您的名字", + "enterLastName": "输入您的姓氏", + "enterConfirmPassword": "输入您的密码进行确认", + "organization": "组织", + "invalidDetailsMessage": "请输入有效的详细信息。" + }, + "userListCard": { + "addAdmin": "添加管理员", + "addedAsAdmin": "用户被添加为管理员。" + }, + "orgAdminListCard": { + "remove": "消除", + "removeAdmin": "删除管理员", + "removeAdminMsg": "您想删除该管理员吗?", + "adminRemoved": "管理员被删除。" + }, + "orgPeopleListCard": { + "remove": "消除", + "removeMember": "删除会员", + "removeMemberMsg": "您想删除该成员吗?", + "memberRemoved": "该会员已被删除" + }, + "organizationEvents": { + "title": "活动", + "filterByTitle": "按标题过滤", + "filterByLocation": "按地点过滤", + "filterByDescription": "按描述过滤", + "addEvent": "添加事件", + "eventDetails": "活动详情", + "eventTitle": "标题", + "startTime": "开始时间", + "endTime": "时间结束", + "allDay": "一整天", + "recurringEvent": "重复事件", + "isPublic": "是公开的", + "isRegistrable": "可注册", + "createEvent": "创建事件", + "enterFilter": "输入过滤器", + "enterTitle": "输入标题", + "enterDescrip": "输入描述", + "eventLocation": "输入位置", + "searchEventName": "搜索活动名称", + "eventType": "事件类型", + "eventCreated": "恭喜!", + "customRecurrence": "自定义重复", + "repeatsEvery": "重复每个", + "repeatsOn": "重复开启", + "ends": "结束", + "never": "绝不", + "on": "在", + "after": "后", + "occurences": "事件" + }, + "organizationActionItems": { + "actionItemCategory": "行动项目类别", + "actionItemDetails": "行动项目详情", + "actionItemCompleted": "行动项目已完成", + "assignee": "受让人", + "assigner": "转让人", + "assignmentDate": "分配日期", + "active": "积极的", + "clearFilters": "清除过滤器", + "completed": "完全的", + "completionDate": "完成日期", + "createActionItem": "创建操作项", + "deleteActionItem": "删除操作项", + "deleteActionItemMsg": "您想删除此操作项吗?", + "details": "细节", + "dueDate": "到期日", + "earliest": "最早", + "editActionItem": "编辑操作项", + "isCompleted": "完全的", + "latest": "最新的", + "makeActive": "积极的", + "noActionItems": "无行动项目", + "options": "选项", + "preCompletionNotes": "预完成注释", + "actionItemActive": "积极的", + "markCompletion": "标记完成", + "actionItemStatus": "行动项目状态", + "postCompletionNotes": "完成后注释", + "selectActionItemCategory": "选择操作项类别", + "selectAssignee": "选择受托人", + "status": "地位", + "successfulCreation": "操作项创建成功", + "successfulUpdation": "操作项已成功更新", + "successfulDeletion": "操作项已成功删除", + "title": "行动项目" + }, + "organizationAgendaCategory": { + "agendaCategoryDetails": "议程类别详情", + "updateAgendaCategory": "更新议程类别", + "title": "议程类别", + "name": "类别", + "description": "描述", + "createdBy": "创建人", + "options": "选项", + "createAgendaCategory": "创建议程类别", + "noAgendaCategories": "没有议程类别", + "update": "更新", + "agendaCategoryCreated": "议程类别创建成功", + "agendaCategoryUpdated": "议程类别更新成功", + "agendaCategoryDeleted": "议程类别删除成功", + "deleteAgendaCategory": "删除议程类别", + "deleteAgendaCategoryMsg": "是否要删除此议程类别?" + }, + "agendaItems": { + "agendaItemDetails": "议程项目详细信息", + "updateAgendaItem": "更新议程项目", + "title": "标题", + "enterTitle": "输入标题", + "sequence": "顺序", + "description": "描述", + "enterDescription": "输入描述", + "category": "议程类别", + "attachments": "附件", + "attachmentLimit": "添加任何图像文件或视频文件,最大 10MB", + "fileSizeExceedsLimit": "文件大小超过 10MB 的限制", + "urls": "网址", + "url": "添加链接到网址", + "enterUrl": "https://example.com", + "invalidUrl": "请输入有效的网址", + "link": "链接", + "createdBy": "创建人", + "regular": "常规", + "note": "注意", + "duration": "持续时间", + "enterDuration": "分:秒", + "options": "选项", + "createAgendaItem": "创建议程项目", + "noAgendaItems": "没有议程项目", + "selectAgendaItemCategory": "选择议程项目类别", + "update": "更新", + "delete": "删除", + "agendaItemCreated": "议程项目已成功创建", + "agendaItemUpdated": "议程项目已成功更新", + "agendaItemDeleted": "议程项目已成功删除", + "deleteAgendaItem": "删除议程项目", + "deleteAgendaItemMsg": "您要删除此议程项目吗?" + }, + "eventListCard": { + "deleteEvent": "删除事件", + "deleteEventMsg": "您想删除此事件吗?", + "editEvent": "编辑事件", + "eventTitle": "标题", + "alreadyRegistered": "已经注册", + "startTime": "开始时间", + "endTime": "时间结束", + "allDay": "一整天", + "recurringEvent": "重复事件", + "isPublic": "是公开的", + "isRegistrable": "可注册", + "updatePost": "更新帖子", + "eventDetails": "活动详情", + "eventDeleted": "活动删除成功。", + "eventUpdated": "活动更新成功。", + "thisInstance": "本实例", + "thisAndFollowingInstances": "本实例及后续实例", + "allInstances": "所有实例", + "customRecurrence": "自定义重复", + "repeatsEvery": "重复每个", + "repeatsOn": "重复开启", + "ends": "结束", + "never": "绝不", + "on": "在", + "after": "后", + "occurences": "事件" + }, + "funds": { + "title": "基金", + "createFund": "创建基金", + "fundName": "基金名称", + "fundId": "基金(参考)ID", + "taxDeductible": "税前扣除", + "default": "默认", + "archived": "已归档", + "fundCreate": "创建基金", + "fundUpdate": "更新基金", + "fundDelete": "删除基金", + "searchByName": "按名称搜索", + "noFundsFound": "未找到基金", + "createdBy": "由...创建", + "createdOn": "创建于", + "status": "状态", + "fundCreated": "基金创建成功", + "fundUpdated": "基金更新成功", + "fundDeleted": "基金删除成功", + "deleteFundMsg": "您确定要删除此基金吗?", + "createdLatest": "最近创建", + "createdEarliest": "最早创建", + "viewCampaigns": "查看活动" + }, + "fundCampaign": { + "title": "募捐活动", + "campaignName": "活动名称", + "campaignOptions": "选项", + "fundingGoal": "资金目标", + "addCampaign": "添加活动", + "createdCampaign": "活动创建成功", + "updatedCampaign": "活动更新成功", + "deletedCampaign": "活动删除成功", + "deleteCampaignMsg": "您确定要删除此活动吗?", + "noCampaigns": "未找到活动", + "createCampaign": "创建活动", + "updateCampaign": "更新活动", + "deleteCampaign": "删除活动", + "currency": "货币", + "selectCurrency": "选择货币", + "searchFullName": "按名称搜索", + "viewPledges": "查看承诺", + "noCampaignsFound": "未找到活动", + "latestEndDate": "最新结束日期", + "earliestEndDate": "最早结束日期", + "lowestGoal": "最低目标", + "highestGoal": "最高目标" + }, + "pledges": { + "title": "基金活动承诺", + "pledgeAmount": "质押金额", + "pledgeOptions": "选项", + "pledgeCreated": "质押创建成功", + "pledgeUpdated": "承诺更新成功", + "pledgeDeleted": "承诺删除成功", + "addPledge": "添加承诺", + "createPledge": "创建承诺", + "currency": "货币", + "selectCurrency": "选择货币", + "updatePledge": "更新承诺", + "deletePledge": "删除承诺", + "amount": "数量", + "editPledge": "编辑承诺", + "deletePledgeMsg": "您确定要删除此承诺吗?", + "noPledges": "未找到承诺", + "searchPledger": "按承诺搜索", + "highestAmount": "最高金额", + "lowestAmount": "最低金额", + "latestEndDate": "最新结束日期", + "earliestEndDate": "最早结束日期", + "campaigns": "活动", + "pledges": "承诺", + "endsOn": "结束于", + "raisedAmount": "募集金額", + "pledgedAmount": "承诺金額" + }, + "orgPost": { + "title": "帖子", + "searchPost": "搜索帖子", + "posts": "帖子", + "createPost": "创建帖子", + "postDetails": "帖子详情", + "postTitle1": "写下帖子的标题", + "postTitle": "标题", + "addMedia": "上传媒体", + "information": "信息", + "information1": "填写帖子信息", + "addPost": "添加帖子", + "searchTitle": "按标题搜索", + "searchText": "按文本搜索", + "ptitle": "帖子标题", + "postDes": "你要聊什么?", + "Title": "标题", + "Text": "文本", + "searchBy": "搜索依据", + "Oldest": "最旧的在前", + "Latest": "最新第一", + "sortPost": "排序帖子", + "tag": " 您的浏览器不支持video标签", + "postCreatedSuccess": "恭喜!", + "pinPost": "针柱", + "Next": "下一页", + "Previous": "上一页" + }, + "postNotFound": { + "post": "邮政", + "not found!": "未找到!", + "organization": "组织", + "post not found!": "帖子未找到!", + "organization not found!": "未找到组织!" + }, + "userNotFound": { + "not found!": "未找到!", + "roles": "角色", + "user not found!": "未找到用户!", + "member not found!": "未找到会员!", + "admin not found!": "找不到管理员!", + "roles not found!": "未找到角色!" + }, + "orgPostCard": { + "author": "作者", + "imageURL": "图片网址", + "videoURL": "视频网址", + "deletePost": "删除帖子", + "deletePostMsg": "您想删除此帖子吗?", + "editPost": "编辑帖子", + "postTitle": "标题", + "postTitle1": "编辑帖子标题", + "information1": "编辑帖子信息", + "information": "信息", + "image": "图像", + "video": "视频", + "updatePost": "更新帖子", + "postDeleted": "帖子删除成功。", + "postUpdated": "帖子更新成功。", + "tag": " 您的浏览器不支持video标签", + "pin": "针柱" + }, + "blockUnblockUser": { + "title": "阻止/取消阻止用户", + "pageName": "阻止/解除阻止", + "listOfUsers": "发送垃圾邮件的用户列表", + "block_unblock": "阻止/解除阻止", + "unblock": "解锁", + "block": "堵塞", + "orgName": "输入名字", + "blockedSuccessfully": "用户被成功屏蔽", + "Un-BlockedSuccessfully": "用户解封成功", + "allMembers": "所有会员", + "blockedUsers": "被阻止的用户", + "searchByFirstName": "按名字搜索", + "searchByLastName": "按姓氏搜索", + "noSpammerFound": "未发现垃圾邮件发送者" + }, + "eventManagement": { + "title": "事件管理", + "dashboard": "仪表板", + "registrants": "注册者", + "eventActions": "事件动作", + "eventAgendas": "活动议程", + "eventStats": "事件统计", + "to": "到" + }, + "forgotPassword": { + "title": "塔拉瓦 忘记密码", + "registeredEmail": "注册的电子邮件", + "getOtp": "获取一次性密码", + "enterOtp": "输入一次性密码", + "enterNewPassword": "输入新密码", + "cofirmNewPassword": "确认新密码", + "changePassword": "更改密码", + "backToLogin": "回到登入", + "userOtp": "例如", + "emailNotRegistered": "电子邮件未注册。", + "errorSendingMail": "发送邮件时出错。", + "passwordMismatches": "密码和确认密码不匹配。", + "passwordChanges": "密码修改成功。", + "OTPsent": "OTP 已发送至您的注册邮箱。" + }, + "pageNotFound": { + "404": "404", + "title": "404 未找到", + "talawaAdmin": "塔拉瓦管理员", + "talawaUser": "塔拉瓦用户", + "notFoundMsg": "哎呀!", + "backToHome": "返回首页" + }, + "orgContribution": { + "title": "塔拉瓦 贡献", + "filterByName": "按名称过滤", + "filterByTransId": "按反式过滤。 ", + "recentStats": "最近的统计数据", + "contribution": "贡献", + "orgname": "输入名字", + "searchtransaction": "输入交易ID" + }, + "contriStats": { + "recentContribution": "最近的贡献", + "highestContribution": "最高贡献", + "totalContribution": "总贡献" + }, + "orgContriCards": { + "date": "日期", + "transactionId": "交易ID", + "amount": "数量" + }, + "orgSettings": { + "title": "设置", + "general": "一般的", + "actionItemCategories": "行动项目类别", + "updateOrganization": "更新组织", + "seeRequest": "查看请求", + "noData": "没有数据", + "otherSettings": "其他设置", + "changeLanguage": "改变语言", + "manageCustomFields": "管理自定义字段" + }, + "deleteOrg": { + "deleteOrganization": "删除组织", + "deleteSampleOrganization": "删除样本组织", + "deleteMsg": "您想删除该组织吗?", + "confirmDelete": "确认删除", + "longDelOrgMsg": "通过单击“删除组织”按钮,该组织及其事件、标签和所有相关数据将被永久删除。", + "successfullyDeletedSampleOrganization": "已成功删除样本组织" + }, + "userUpdate": { + "appLanguageCode": "默认语言", + "userType": "用户类型" + }, + "userPasswordUpdate": { + "previousPassword": "旧密码", + "newPassword": "新密码", + "confirmNewPassword": "确认新密码", + "passCantBeEmpty": "密码不能为空", + "passNoMatch": "新密码和确认密码不匹配。" + }, + "orgDelete": { + "deleteOrg": "删除组织" + }, + "membershipRequest": { + "accept": "接受", + "reject": "拒绝", + "memberAdded": "它被接受" + }, + "orgUpdate": { + "city": "城市", + "countryCode": "国家代码", + "line1": "1号线", + "line2": "2号线", + "postalCode": "邮政编码", + "dependentLocality": "附属地点", + "sortingCode": "排序代码", + "state": "州/省", + "userRegistrationRequired": "需要用户注册", + "isVisibleInSearch": "在搜索中可见", + "enterNameOrganization": "输入组织名称", + "successfulUpdated": "组织更新成功" + }, + "addOnRegister": { + "addNew": "添新", + "addPlugin": "添加插件", + "pluginName": "插件名称", + "creatorName": "创建者姓名", + "pluginDesc": "插件说明", + "pName": "例如:捐款", + "cName": "例如:约翰·多伊", + "pDesc": "该插件启用 UI" + }, + "addOnStore": { + "title": "添加商店", + "searchName": "例如:捐款", + "search": "搜索", + "enable": "启用", + "disable": "残疾人", + "pHeading": "插件", + "install": "已安装", + "available": "可用的", + "pMessage": "插件不存在" + }, + "addOnEntry": { + "enable": "启用", + "install": "安装", + "uninstall": "卸载", + "uninstallMsg": "此功能现已从您的组织中删除", + "installMsg": "您的组织现已启用此功能" + }, + "memberDetail": { + "title": "用户详细信息", + "addAdmin": "添加管理员", + "alreadyIsAdmin": "会员已经是管理员", + "organizations": "组织机构", + "events": "活动", + "role": "角色", + "createdOn": "创建于", + "main": "主要的", + "firstName": "名", + "lastName": "姓", + "language": "语言", + "gender": "性别", + "birthDate": "出生日期", + "educationGrade": "教育等级", + "employmentStatus": "就业状况", + "maritalStatus": "婚姻状况", + "phone": "电话", + "countryCode": "国家代码", + "state": "状态", + "city": "城市", + "personalInfoHeading": "个人信息", + "contactInfoHeading": "联系信息", + "actionsHeading": "行动", + "personalDetailsHeading": "个人资料详情", + "appLanguageCode": "选择语言", + "deleteUser": "删除用户", + "pluginCreationAllowed": "允许创建插件", + "created": "已创建", + "adminForOrganizations": "组织管理员", + "membershipRequests": "会员请求", + "adminForEvents": "活动管理员", + "addedAsAdmin": "用户被添加为管理员。", + "userType": "用户类型" + }, + "userLogin": { + "login": "登录", + "loginIntoYourAccount": "登录您的帐户", + "invalidDetailsMessage": "请输入有效的电子邮件和密码。", + "notAuthorised": "对不起!", + "invalidCredentials": "输入的凭据不正确。" + }, + "userRegister": { + "enterFirstName": "输入您的名字", + "enterLastName": "输入您的姓氏", + "enterConfirmPassword": "输入您的密码进行确认", + "alreadyhaveAnAccount": "已经有帐户?", + "login": "登录", + "afterRegister": "注册成功。", + "passwordNotMatch": "密码不匹配。", + "invalidDetailsMessage": "请输入有效的详细信息。" + }, + "userNavbar": { + "talawa": "塔拉瓦", + "home": "家", + "people": "人们", + "events": "活动", + "chat": "聊天", + "donate": "捐", + "language": "语言" + }, + "userOrganizations": { + "allOrganizations": "所有组织", + "joinedOrganizations": "加入组织", + "createdOrganizations": "创建组织", + "selectOrganization": "选择一个组织", + "searchUsers": "搜索用户", + "nothingToShow": "这里没有什么可显示的。", + "organizations": "组织机构" + }, + "userSidebarOrg": { + "yourOrganizations": "您的组织", + "noOrganizations": "您还没有加入任何组织。", + "viewAll": "查看全部", + "talawaUserPortal": "塔拉瓦用户门户", + "my organizations": "我的组织", + "communityProfile": "社区简介" + }, + "organizationSidebar": { + "viewAll": "查看全部", + "events": "活动", + "noEvents": "没有可显示的活动", + "noMembers": "没有可显示的会员" + }, + "postCard": { + "likes": "喜欢", + "comments": "评论", + "viewPost": "查看帖子", + "editPost": "编辑帖子", + "postedOn": "发布于 {{date}}" + }, + "home": { + "posts": "帖子", + "post": "邮政", + "title": "标题", + "textArea": "你有什么心事吗?", + "feed": "喂养", + "loading": "加载中", + "pinnedPosts": "已标记的帖子", + "yourFeed": "您的动态", + "nothingToShowHere": "这里没有可显示的内容", + "somethingOnYourMind": "你有什么心事吗?", + "addPost": "添加帖子", + "startPost": "开始发帖", + "media": "媒体", + "event": "事件", + "article": "文章", + "postNowVisibleInFeed": "帖子现在在动态中可见" + }, + "settings": { + "profileSettings": "配置文件设置", + "gender": "性别", + "phoneNumber": "电话号码", + "chooseFile": "选择文件", + "birthDate": "出生日期", + "grade": "教育等级", + "empStatus": "就业状况", + "maritalStatus": "婚姻状况", + "state": "市,州", + "country": "国家", + "resetChanges": "重置更改", + "profileDetails": "个人资料详情", + "deleteUserMessage": "通过单击“删除用户”按钮,您的用户及其事件、标签和所有相关数据将被永久删除。", + "copyLink": "复制个人资料链接", + "deleteUser": "删除用户", + "otherSettings": "其他设置", + "changeLanguage": "改变语言", + "sgender": "选择性别", + "gradePlaceholder": "输入年级", + "sEmpStatus": "选择就业状况", + "female": "女性", + "male": "男性", + "employed": "就业", + "other": "其他", + "sMaritalStatus": "选择婚姻状况", + "unemployed": "失业", + "married": "已婚", + "single": "单身的", + "widowed": "寡", + "divorced": "离婚", + "engaged": "已订婚的", + "separated": "分离的", + "grade1": "1级", + "grade2": "二年级", + "grade3": "三年级", + "grade4": "四年级", + "grade5": "五年级", + "grade6": "6年级", + "grade7": "7年级", + "grade8": "8级", + "grade9": "9年级", + "grade10": "10年级", + "grade11": "11年级", + "grade12": "12年级", + "graduate": "毕业", + "kg": "公斤", + "preKg": "预幼稚园", + "noGrade": "无等级", + "fullTime": "全职", + "partTime": "兼职", + "selectCountry": "选择一个国家", + "enterState": "输入城市或州" + }, + "donate": { + "donations": "捐款", + "searchDonations": "搜索捐款", + "donateForThe": "为", + "amount": "数量", + "yourPreviousDonations": "您之前的捐款", + "donate": "捐", + "nothingToShow": "这里没有什么可显示的。", + "success": "捐赠成功" + }, + "userEvents": { + "nothingToShow": "这里没有什么可显示的。", + "createEvent": "创建事件", + "recurring": "重复事件", + "startTime": "开始时间", + "endTime": "时间结束", + "listView": "列表显示", + "calendarView": "日历视图", + "allDay": "一整天", + "eventCreated": "活动已成功创建并发布。", + "eventDetails": "活动详情", + "eventTitle": "标题", + "enterTitle": "输入标题", + "enterDescription": "输入描述", + "enterLocation": "输入位置", + "publicEvent": "是公开的", + "registerable": "可注册", + "monthlyCalendarView": "月历", + "yearlyCalendarView": "年历" + }, + "userEventCard": { + "starts": "开始", + "ends": "结束", + "creator": "创作者", + "alreadyRegistered": "已经注册" + }, + "advertisement": { + "title": "广告", + "activeAds": "活跃活动", + "archievedAds": "已完成的活动", + "pMessage": "此活动中不存在广告。", + "validLink": "链接有效", + "invalidLink": "链接无效", + "Rname": "输入广告名称", + "Rtype": "选择广告类型", + "Rmedia": "提供要显示的媒体内容", + "RstartDate": "选择开始日期", + "RendDate": "选择结束日期", + "RClose": "关上窗户", + "addNew": "制作新广告", + "EXname": "前任。", + "EXlink": "前任。 ", + "createAdvertisement": "创建广告", + "deleteAdvertisement": "删除广告", + "deleteAdvertisementMsg": "您想删除该广告吗?", + "view": "看法", + "editAdvertisement": "编辑广告", + "advertisementDeleted": "广告已成功删除。", + "endDateGreaterOrEqual": "结束日期应大于或等于开始日期", + "advertisementCreated": "广告已成功创建。" + }, + "userChat": { + "chat": "聊天", + "contacts": "联系方式" + }, + "userChatRoom": { + "selectContact": "选择联系人开始对话", + "sendMessage": "发信息" + }, + "orgProfileField": { + "loading": "加载中...", + "noCustomField": "没有可用的自定义字段", + "customFieldName": "字段名称", + "enterCustomFieldName": "输入字段名称", + "customFieldType": "字段类型", + "Remove Custom Field": "删除自定义字段", + "fieldSuccessMessage": "字段添加成功", + "fieldRemovalSuccess": "字段删除成功", + "String": "字符串", + "Boolean": "布尔值", + "Date": "日期", + "Number": "数字" + }, + "orgActionItemCategories": { + "enableButton": "使能够", + "disableButton": "禁用", + "updateActionItemCategory": "更新", + "actionItemCategoryName": "姓名", + "actionItemCategoryDetails": "行动项目类别详细信息", + "enterName": "输入名字", + "successfulCreation": "操作项类别创建成功", + "successfulUpdation": "行动项目类别已成功更新", + "sameNameConflict": "请更改名称以进行更新", + "categoryEnabled": "已启用操作项类别", + "categoryDisabled": "操作项类别已禁用" + }, + "organizationVenues": { + "title": "场地", + "addVenue": "添加场地", + "venueDetails": "场地详情", + "venueName": "场地名称", + "enterVenueName": "输入场地名称", + "enterVenueDesc": "输入场地描述", + "capacity": "容量", + "enterVenueCapacity": "输入场地容量", + "image": "场地图片", + "uploadVenueImage": "上传场地图片", + "createVenue": "创建场地", + "venueAdded": "场地添加成功", + "editVenue": "更新地点", + "venueUpdated": "场地详情更新成功", + "sort": "种类", + "highestCapacity": "最高容量", + "lowestCapacity": "最低容量", + "noVenues": "未找到场地!", + "view": "看法", + "venueTitleError": "场地名称不能为空!", + "venueCapacityError": "容量必须是正数!", + "searchBy": "搜索依据" + }, + "addMember": { + "title": "添加会员", + "addMembers": "添加会员", + "existingUser": "现有用户", + "newUser": "新用户", + "searchFullName": "按全名搜索", + "enterFirstName": "输入名字", + "enterLastName": "输入姓氏", + "enterConfirmPassword": "输入确认密码", + "organization": "组织", + "invalidDetailsMessage": "请提供所有必需的详细信息。", + "passwordNotMatch": "密码不匹配。", + "addMember": "添加会员" + }, + "eventActionItems": { + "title": "行动项目", + "createActionItem": "创建行动项目", + "actionItemCategory": "行动项目类别", + "selectActionItemCategory": "选择操作项类别", + "selectAssignee": "选择受托人", + "preCompletionNotes": "笔记", + "postCompletionNotes": "完成说明", + "actionItemDetails": "行动项目详情", + "dueDate": "到期日", + "completionDate": "完成日期", + "editActionItem": "编辑操作项", + "deleteActionItem": "删除操作项", + "deleteActionItemMsg": "您想删除此操作项吗?", + "successfulDeletion": "操作项已成功删除", + "successfulCreation": "操作项创建成功", + "successfulUpdation": "操作项已成功更新", + "notes": "笔记", + "assignee": "受让人", + "assigner": "分配者", + "assignmentDate": "任务分配日期", + "status": "地位", + "actionItemActive": "积极的", + "actionItemStatus": "行动项目状态", + "actionItemCompleted": "行动项目已完成", + "markCompletion": "标记完成", + "save": "节省" + }, + "checkIn": { + "errorCheckingIn": "签到错误", + "checkedInSuccessfully": "成功签到" + }, + "eventRegistrantsModal": { + "errorAddingAttendee": "添加与会者时出错", + "errorRemovingAttendee": "删除与会者时出错" + } +} diff --git a/public/logo192.png b/public/logo192.png deleted file mode 100644 index fc44b0a379..0000000000 Binary files a/public/logo192.png and /dev/null differ diff --git a/public/manifest.json b/public/manifest.json index 080d6c77ac..23e6e6efe4 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -10,10 +10,10 @@ { "src": "logo192.png", "type": "image/png", - "sizes": "192x192" + "sizes": "16x16" }, { - "src": "logo512.png", + "src": "images/logo512.png", "type": "image/png", "sizes": "512x512" } diff --git a/public/markdown/images/install1.png b/public/markdown/images/install1.png new file mode 100644 index 0000000000..632cb4f7a5 Binary files /dev/null and b/public/markdown/images/install1.png differ diff --git a/public/markdown/images/install2.png b/public/markdown/images/install2.png new file mode 100644 index 0000000000..308cfdbd56 Binary files /dev/null and b/public/markdown/images/install2.png differ diff --git a/schema.graphql b/schema.graphql new file mode 100644 index 0000000000..6e00550083 --- /dev/null +++ b/schema.graphql @@ -0,0 +1,1584 @@ +directive @auth on FIELD_DEFINITION + +directive @role(requires: UserType) on FIELD_DEFINITION + +type ActionItem { + _id: ID! + actionItemCategory: ActionItemCategory + assignee: User + assigner: User + assignmentDate: Date! + completionDate: Date! + createdAt: Date! + creator: User + dueDate: Date! + event: Event + isCompleted: Boolean! + postCompletionNotes: String + preCompletionNotes: String + updatedAt: Date! +} + +type ActionItemCategory { + _id: ID! + createdAt: Date! + creator: User + isDisabled: Boolean! + name: String! + organization: Organization + updatedAt: Date! +} + +type Address { + city: String + countryCode: String + dependentLocality: String + line1: String + line2: String + postalCode: String + sortingCode: String + state: String +} + +input AddressInput { + city: String + countryCode: String + dependentLocality: String + line1: String + line2: String + postalCode: String + sortingCode: String + state: String +} + +type Advertisement { + _id: ID! + createdAt: DateTime! + creator: User + endDate: Date! + mediaUrl: URL! + name: String! + orgId: ID! + startDate: Date! + type: AdvertisementType! + updatedAt: DateTime! +} + +enum AdvertisementType { + BANNER + MENU + POPUP +} + +type AdvertisementEdge { + cursor: String + node: Advertisement +} + +type AdvertisementsConnection { + edges: [AdvertisementEdge] + pageInfo: DefaultConnectionPageInfo + totalCount: Int +} + +type AgendaCategory { + _id: ID! + createdAt: Date! + createdBy: User! + description: String + name: String! + organization: Organization! + updatedAt: Date + updatedBy: User +} + +type AggregatePost { + count: Int! +} + +type AggregateUser { + count: Int! +} + +scalar Any + +type AppUserProfile { + _id: ID! + adminFor: [Organization] + appLanguageCode: String! + createdEvents: [Event] + createdOrganizations: [Organization] + eventAdmin: [Event] + isSuperAdmin: Boolean! + pluginCreationAllowed: Boolean! + userId: User! +} + +type AuthData { + accessToken: String! + appUserProfile: AppUserProfile! + refreshToken: String! + user: User! +} + +type CheckIn { + _id: ID! + allotedRoom: String + allotedSeat: String + createdAt: DateTime! + event: Event! + feedbackSubmitted: Boolean! + time: DateTime! + updatedAt: DateTime! + user: User! +} + +input CheckInInput { + allotedRoom: String + allotedSeat: String + eventId: ID! + userId: ID! +} + +type CheckInStatus { + _id: ID! + checkIn: CheckIn + user: User! +} + +type Comment { + _id: ID! + createdAt: DateTime! + creator: User + likeCount: Int + likedBy: [User] + post: Post! + text: String! + updatedAt: DateTime! +} + +input CommentInput { + text: String! +} + +union ConnectionError = InvalidCursor | MaximumValueError + +type ConnectionPageInfo { + endCursor: String + hasNextPage: Boolean! + hasPreviousPage: Boolean! + startCursor: String +} + +scalar CountryCode + +input CreateActionItemInput { + assigneeId: ID! + dueDate: Date + eventId: ID + preCompletionNotes: String +} + +input CreateAgendaCategoryInput { + description: String + name: String! + organizationId: ID! +} + +input CreateUserTagInput { + name: String! + organizationId: ID! + parentTagId: ID +} + +input CursorPaginationInput { + cursor: String + direction: PaginationDirection! + limit: PositiveInt! +} + +scalar Date + +scalar DateTime + +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! + createdAt: DateTime! + nameOfOrg: String! + nameOfUser: String! + orgId: ID! + payPalId: String! + updatedAt: DateTime! + userId: ID! +} + +input DonationWhereInput { + id: ID + id_contains: ID + id_in: [ID!] + id_not: ID + id_not_in: [ID!] + id_starts_with: ID + name_of_user: String + name_of_user_contains: String + name_of_user_in: [String!] + name_of_user_not: String + name_of_user_not_in: [String!] + name_of_user_starts_with: String +} + +enum EducationGrade { + GRADE_1 + GRADE_2 + GRADE_3 + GRADE_4 + GRADE_5 + GRADE_6 + GRADE_7 + GRADE_8 + GRADE_9 + GRADE_10 + GRADE_11 + GRADE_12 + GRADUATE + KG + NO_GRADE + PRE_KG +} + +scalar EmailAddress + +enum EmploymentStatus { + FULL_TIME + PART_TIME + UNEMPLOYED +} + +interface Error { + message: String! +} + +type Event { + _id: ID! + actionItems: [ActionItem] + admins(adminId: ID): [User!] + allDay: Boolean! + attendees: [User] + attendeesCheckInStatus: [CheckInStatus!]! + averageFeedbackScore: Float + createdAt: DateTime! + creator: User + description: String! + endDate: Date + endTime: Time + feedback: [Feedback!]! + isPublic: Boolean! + isRegisterable: Boolean! + latitude: Latitude + location: String + longitude: Longitude + organization: Organization + recurrance: Recurrance + recurring: Boolean! + startDate: Date! + startTime: Time + status: Status! + title: String! + updatedAt: DateTime! +} + +input EventAttendeeInput { + eventId: ID! + userId: ID! +} + +input EventInput { + allDay: Boolean! + description: String! + endDate: Date + endTime: Time + isPublic: Boolean! + isRegisterable: Boolean! + latitude: Latitude + location: String + longitude: Longitude + organizationId: ID! + recurrance: Recurrance + recurring: Boolean! + startDate: Date! + startTime: Time + title: String! +} + +enum EventOrderByInput { + allDay_ASC + allDay_DESC + description_ASC + description_DESC + endDate_ASC + endDate_DESC + endTime_ASC + endTime_DESC + id_ASC + id_DESC + location_ASC + location_DESC + recurrance_ASC + recurrance_DESC + startDate_ASC + startDate_DESC + startTime_ASC + startTime_DESC + title_ASC + title_DESC +} + +type EventVolunteer { + _id: ID! + createdAt: DateTime! + creator: User + event: Event + isAssigned: Boolean + isInvited: Boolean + response: String + updatedAt: DateTime! + user: User! +} + +input EventVolunteerInput { + eventId: ID! + userId: ID! +} + +enum EventVolunteerResponse { + NO + YES +} + +input EventWhereInput { + description: String + description_contains: String + description_in: [String!] + description_not: String + description_not_in: [String!] + description_starts_with: String + id: ID + id_contains: ID + id_in: [ID!] + id_not: ID + id_not_in: [ID!] + id_starts_with: ID + location: String + location_contains: String + location_in: [String!] + location_not: String + location_not_in: [String!] + location_starts_with: String + organization_id: ID + title: String + title_contains: String + title_in: [String!] + title_not: String + title_not_in: [String!] + title_starts_with: String +} + +type ExtendSession { + accessToken: String! + refreshToken: String! +} + +type Feedback { + _id: ID! + createdAt: DateTime! + event: Event! + rating: Int! + review: String + updatedAt: DateTime! +} + +input FeedbackInput { + eventId: ID! + rating: Int! + review: String +} + +interface FieldError { + message: String! + path: [String!]! +} + +input ForgotPasswordData { + newPassword: String! + otpToken: String! + userOtp: String! +} + +enum Frequency { + DAILY + MONTHLY + WEEKLY + YEARLY +} + +enum Gender { + FEMALE + MALE + OTHER +} + +type Group { + _id: ID! + admins: [User!]! + createdAt: DateTime! + description: String + organization: Organization! + title: String! + 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!]! +} + +scalar JSON + +type Language { + _id: ID! + createdAt: String! + en: String! + translation: [LanguageModel] +} + +input LanguageInput { + en_value: String! + translation_lang_code: String! + translation_value: String! +} + +type LanguageModel { + _id: ID! + createdAt: DateTime! + lang_code: String! + value: String! + verified: Boolean! +} + +scalar Latitude + +input LoginInput { + email: EmailAddress! + password: String! +} + +scalar Longitude + +enum MaritalStatus { + DIVORCED + ENGAGED + MARRIED + SEPERATED + SINGLE + WIDOWED +} + +type MaximumLengthError implements FieldError { + message: String! + path: [String!]! +} + +type MaximumValueError implements FieldError { + limit: Int! + message: String! + path: [String!]! +} + +type MembershipRequest { + _id: ID! + organization: Organization! + 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! + path: [String!]! +} + +type MinimumValueError implements FieldError { + message: String! + path: [String!]! +} + +enum AdvertisementType { + BANNER + MENU + POPUP +} + +input CreateAdvertisementInput { + endDate: Date! + name: String! + organizationId: ID! + startDate: Date! + type: AdvertisementType! + mediaFile: String! +} + +type CreateAdvertisementPayload { + advertisement: Advertisement +} + +input EditVenueInput { + capacity: Int + description: String + file: String + id: ID! + name: String +} + +type Mutation { + acceptMembershipRequest(membershipRequestId: ID!): MembershipRequest! + addEventAttendee(data: EventAttendeeInput!): User! + addFeedback(data: FeedbackInput!): Feedback! + addLanguageTranslation(data: LanguageInput!): Language! + addOrganizationCustomField( + name: String! + organizationId: ID! + type: String! + ): OrganizationCustomField! + addOrganizationImage(file: String!, organizationId: String!): Organization! + addUserCustomData( + dataName: String! + dataValue: Any! + 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! + userId: ID! + ): AppUserProfile! + blockUser(organizationId: ID!, userId: ID!): User! + cancelMembershipRequest(membershipRequestId: ID!): MembershipRequest! + checkIn(data: CheckInInput!): CheckIn! + createActionItem( + actionItemCategoryId: ID! + data: CreateActionItemInput! + ): ActionItem! + createActionItemCategory( + name: String! + organizationId: ID! + ): ActionItemCategory! + createAdmin(data: UserAndOrganizationInput!): AppUserProfile! + createAdvertisement( + endDate: Date! + link: String! + name: String! + orgId: ID! + startDate: Date! + type: String! + ): Advertisement! + createAgendaCategory(input: CreateAgendaCategoryInput!): AgendaCategory! + createComment(data: CommentInput!, postId: ID!): Comment + createDirectChat(data: createChatInput!): DirectChat! + createDonation( + amount: Float! + nameOfOrg: String! + nameOfUser: String! + orgId: ID! + payPalId: ID! + userId: ID! + ): Donation! + createEvent( + data: EventInput! + 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! + pluginDesc: String! + pluginName: String! + uninstalledOrgs: [ID!] + ): Plugin! + createPost(data: PostInput!, file: String): Post + createSampleOrganization: Boolean! + createUserFamily(data: createUserFamilyInput!): UserFamily! + createUserTag(input: CreateUserTagInput!): UserTag + createVenue(data: VenueInput!): Venue + deleteAdvertisement(id: ID!): DeletePayload! + deleteAdvertisementById(id: ID!): DeletePayload! + deleteAgendaCategory(id: ID!): ID! + deleteDonationById(id: ID!): DeletePayload! + deleteVenue(id: ID!): Venue + editVenue(data: EditVenueInput!): Venue + forgotPassword(data: ForgotPasswordData!): Boolean! + joinPublicOrganization(organizationId: ID!): User! + leaveOrganization(organizationId: ID!): User! + likeComment(id: ID!): Comment + likePost(id: ID!): Post + login(data: LoginInput!): AuthData! + logout: Boolean! + otp(data: OTPInput!): OtpData! + recaptcha(data: RecaptchaVerification!): Boolean! + refreshToken(refreshToken: String!): ExtendSession! + registerForEvent(id: ID!): Event! + rejectMembershipRequest(membershipRequestId: ID!): MembershipRequest! + removeActionItem(id: ID!): ActionItem! + 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( + customFieldId: ID! + organizationId: ID! + ): OrganizationCustomField! + removeOrganizationImage(organizationId: String!): Organization! + removePost(id: ID!): Post + 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 + revokeRefreshTokenForUser: Boolean! + saveFcmToken(token: String): Boolean! + sendMembershipRequest(organizationId: ID!): MembershipRequest! + 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 + unblockUser(organizationId: ID!, userId: ID!): User! + unlikeComment(id: ID!): Comment + unlikePost(id: ID!): Post + unregisterForEventByUser(id: ID!): Event! + updateActionItem(data: UpdateActionItemInput!, id: ID!): ActionItem + updateActionItemCategory( + data: UpdateActionItemCategoryInput! + id: ID! + ): ActionItemCategory + updateAdvertisement( + input: UpdateAdvertisementInput! + ): UpdateAdvertisementPayload + updateAgendaCategory( + id: ID! + input: UpdateAgendaCategoryInput! + ): AgendaCategory + updateEvent(data: UpdateEventInput, id: ID!): Event! + updateEventVolunteer( + data: UpdateEventVolunteerInput + id: ID! + ): EventVolunteer! + updateLanguage(languageCode: String!): User! + updateOrganization( + data: UpdateOrganizationInput + file: String + id: ID! + ): Organization! + updatePluginStatus(id: ID!, orgId: ID!): Plugin! + updatePost(data: PostUpdateInput, id: ID!): Post! + updateUserPassword(data: UpdateUserPasswordInput!): UserData! + updateUserProfile(data: UpdateUserInput, file: String): User! + updateUserRoleInOrganization( + organizationId: ID! + role: String! + userId: ID! + ): Organization! + updateUserTag(input: UpdateUserTagInput!): UserTag + updateUserType(data: UpdateUserTypeInput!): Boolean! + venues: [Venue] +} + +input OTPInput { + email: EmailAddress! +} + +type Organization { + _id: ID! + actionItemCategories: [ActionItemCategory] + address: Address + admins(adminId: ID): [User!] + agendaCategories: [AgendaCategory] + apiUrl: URL! + blockedUsers: [User] + createdAt: DateTime! + creator: User + customFields: [OrganizationCustomField!]! + description: String! + image: String + members: [User] + membershipRequests: [MembershipRequest] + name: String! + pinnedPosts: [Post] + updatedAt: DateTime! + userRegistrationRequired: Boolean! + userTags( + after: String + before: String + first: PositiveInt + last: PositiveInt + ): UserTagsConnection + visibleInSearch: Boolean! + venues: [Venue] +} + +type OrganizationCustomField { + _id: ID! + name: String! + organizationId: String! + type: String! +} + +type OrganizationCustomField { + _id: ID! + name: String! + organizationId: String! + type: String! +} + +type OrganizationInfoNode { + _id: ID! + apiUrl: URL! + creator: User + description: String! + image: String + name: String! + userRegistrationRequired: Boolean! + visibleInSearch: Boolean! +} + +input OrganizationInput { + address: AddressInput! + apiUrl: URL + attendees: String + description: String! + image: String + name: String! + userRegistrationRequired: Boolean + visibleInSearch: Boolean +} + +enum OrganizationOrderByInput { + apiUrl_ASC + apiUrl_DESC + createdAt_ASC + createdAt_DESC + description_ASC + description_DESC + id_ASC + id_DESC + name_ASC + name_DESC +} + +input OrganizationWhereInput { + apiUrl: URL + apiUrl_contains: URL + apiUrl_in: [URL!] + apiUrl_not: URL + apiUrl_not_in: [URL!] + apiUrl_starts_with: URL + description: String + description_contains: String + description_in: [String!] + description_not: String + description_not_in: [String!] + description_starts_with: String + id: ID + id_contains: ID + id_in: [ID!] + id_not: ID + id_not_in: [ID!] + id_starts_with: ID + name: String + name_contains: String + name_in: [String!] + name_not: String + name_not_in: [String!] + name_starts_with: String + userRegistrationRequired: Boolean + visibleInSearch: Boolean +} + +type OtpData { + otpToken: String! +} + +""" +Information about pagination in a connection. +""" +type PageInfo { + currPageNo: Int + + """ + When paginating forwards, are there more items? + """ + hasNextPage: Boolean! + + """ + When paginating backwards, are there more items? + """ + hasPreviousPage: Boolean! + nextPageNo: Int + prevPageNo: Int + totalPages: Int +} + +enum PaginationDirection { + BACKWARD + FORWARD +} + +scalar PhoneNumber + +type Plugin { + _id: ID! + pluginCreatedBy: String! + pluginDesc: String! + pluginName: String! + uninstalledOrgs: [ID!] +} + +type PluginField { + createdAt: DateTime! + key: String! + status: Status! + value: String! +} + +input PluginFieldInput { + key: String! + value: String! +} + +input PluginInput { + fields: [PluginFieldInput] + orgId: ID! + pluginKey: String + pluginName: String! + pluginType: Type +} + +scalar PositiveInt + +type Post { + _id: ID + commentCount: Int + comments: [Comment] + createdAt: DateTime! + creator: User + imageUrl: URL + likeCount: Int + likedBy: [User] + organization: Organization! + pinned: Boolean + text: String! + title: String + updatedAt: DateTime! + videoUrl: URL +} + +""" +A connection to a list of items. +""" +type PostConnection { + aggregate: AggregatePost! + + """ + A list of edges. + """ + edges: [Post]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +input PostInput { + _id: ID + imageUrl: URL + organizationId: ID! + pinned: Boolean + text: String! + title: String + videoUrl: URL +} + +enum PostOrderByInput { + commentCount_ASC + commentCount_DESC + createdAt_ASC + createdAt_DESC + id_ASC + id_DESC + imageUrl_ASC + imageUrl_DESC + likeCount_ASC + likeCount_DESC + text_ASC + text_DESC + title_ASC + title_DESC + videoUrl_ASC + videoUrl_DESC +} + +input PostUpdateInput { + imageUrl: String + text: String + title: String + videoUrl: String +} + +input PostWhereInput { + id: ID + id_contains: ID + id_in: [ID!] + id_not: ID + id_not_in: [ID!] + id_starts_with: ID + text: String + text_contains: String + text_in: [String!] + text_not: String + text_not_in: [String!] + text_starts_with: String + title: String + title_contains: String + title_in: [String!] + title_not: String + title_not_in: [String!] + title_starts_with: String +} + +type Query { + actionItem(id: ID!): ActionItem + actionItemCategoriesByOrganization(organizationId: ID!): [ActionItemCategory] + actionItemCategory(id: ID!): ActionItemCategory + actionItemsByEvent(eventId: ID!): [ActionItem] + actionItemsByOrganization(organizationId: ID!): [ActionItem] + adminPlugin(orgId: ID!): [Plugin] + agendaCategory(id: ID!): AgendaCategory! + checkAuth: User! + customDataByOrganization(organizationId: ID!): [UserCustomData!]! + customFieldsByOrganization(id: ID!): [OrganizationCustomField] + directChatsByUserID(id: ID!): [DirectChat] + directChatsMessagesByChatID(id: ID!): [DirectChatMessage] + directChatById(id: ID!): DirectChat + groupChatById(id: ID!): DirectChat + groupChatsByUserId(id: ID!): [GroupChat] + event(id: ID!): Event + eventVolunteersByEvent(id: ID!): [EventVolunteer] + eventsByOrganization(id: ID, orderBy: EventOrderByInput): [Event] + eventsByOrganizationConnection( + first: Int + orderBy: EventOrderByInput + skip: Int + where: EventWhereInput + ): [Event!]! + advertisementsConnection(after: String, before: String, first: PositiveInt, last: PositiveInt): AdvertisementsConnection + getDonationById(id: ID!): Donation! + getDonationByOrgId(orgId: ID!): [Donation] + getDonationByOrgIdConnection( + first: Int + orgId: ID! + skip: Int + where: DonationWhereInput + ): [Donation!]! + getPlugins: [Plugin] + getlanguage(lang_code: String!): [Translation] + hasSubmittedFeedback(eventId: ID!, userId: ID!): Boolean + isSampleOrganization(id: ID!): Boolean! + joinedOrganizations(id: ID): [Organization] + me: UserData! + myLanguage: String + fundsByOrganization(organizationId: ID!, where: FundWhereInput): [Fund] + organizations(id: ID, orderBy: OrganizationOrderByInput): [Organization] + organizationsConnection( + first: Int + orderBy: OrganizationOrderByInput + skip: Int + where: OrganizationWhereInput + ): [Organization]! + organizationsMemberConnection( + first: Int + orderBy: UserOrderByInput + orgId: ID! + skip: Int + where: UserWhereInput + ): UserConnection! + plugin(orgId: ID!): [Plugin] + post(id: ID!): Post + postsByOrganization(id: ID!, orderBy: PostOrderByInput): [Post] + postsByOrganizationConnection( + first: Int + id: ID! + orderBy: PostOrderByInput + skip: Int + where: PostWhereInput + ): PostConnection + registeredEventsByUser(id: ID, orderBy: EventOrderByInput): [Event] + registrantsByEvent(id: ID!): [User] + user(id: ID!): UserData! + userLanguage(userId: ID!): String + users( + first: Int + orderBy: UserOrderByInput + skip: Int + where: UserWhereInput + ): [UserData] + usersConnection( + first: Int + orderBy: UserOrderByInput + skip: Int + where: UserWhereInput + ): [UserData]! + venue(id:ID!):[Venue] +} + +input RecaptchaVerification { + recaptchaToken: String! +} + +enum Recurrance { + DAILY + MONTHLY + ONCE + WEEKLY + YEARLY +} + +input RecurrenceRuleInput { + count: Int + frequency: Frequency + weekDays: [WeekDays] +} + +enum Status { + ACTIVE + BLOCKED + DELETED +} + +type Subscription { + directMessageChat: MessageChat + messageSentToDirectChat(userId: ID!): DirectChatMessage + messageSentToGroupChat(userId: ID!): GroupChatMessage + onPluginUpdate: Plugin +} + +scalar Time + +input ToggleUserTagAssignInput { + tagId: ID! + userId: ID! +} + +type Translation { + en_value: String + lang_code: String + translation: String + verified: Boolean +} + +enum Type { + PRIVATE + UNIVERSAL +} + +scalar URL + +type UnauthenticatedError implements Error { + message: String! +} + +type UnauthorizedError implements Error { + message: String! +} + +input UpdateActionItemCategoryInput { + isDisabled: Boolean + name: String +} + +input UpdateActionItemInput { + assigneeId: ID + completionDate: Date + dueDate: Date + isCompleted: Boolean + postCompletionNotes: String + preCompletionNotes: String +} + +input UpdateAdvertisementInput { + _id: ID! + endDate: Date + link: String + name: String + startDate: Date + type: AdvertisementType +} + +type UpdateAdvertisementPayload { + advertisement: Advertisement +} + +input UpdateAgendaCategoryInput { + description: String + name: String +} + +input UpdateEventInput { + allDay: Boolean + description: String + endDate: Date + endTime: Time + isPublic: Boolean + isRegisterable: Boolean + latitude: Latitude + location: String + longitude: Longitude + recurrance: Recurrance + recurring: Boolean + startDate: Date + startTime: Time + title: String +} + +input UpdateEventVolunteerInput { + eventId: ID + isAssigned: Boolean + isInvited: Boolean + response: EventVolunteerResponse +} + +input UpdateOrganizationInput { + address: AddressInput + description: String + name: String + userRegistrationRequired: Boolean + visibleInSearch: Boolean +} + +input AddressInput { + city: String + countryCode: String + dependentLocality: String + line1: String + line2: String + postalCode: String + sortingCode: String + state: String +} + +enum EducationGrade { + GRADE_1 + GRADE_2 + GRADE_3 + GRADE_4 + GRADE_5 + GRADE_6 + GRADE_7 + GRADE_8 + GRADE_9 + GRADE_10 + GRADE_11 + GRADE_12 + GRADUATE + KG + NO_GRADE + PRE_KG +} + +enum EmploymentStatus { + FULL_TIME + PART_TIME + UNEMPLOYED +} + +enum Gender { + FEMALE + MALE + OTHER +} + +enum MaritalStatus { + DIVORCED + ENGAGED + MARRIED + SEPERATED + SINGLE + WIDOWED +} + +input UpdateUserInput { + address: AddressInput + birthDate: Date + educationGrade: EducationGrade + email: EmailAddress + employmentStatus: EmploymentStatus + firstName: String + gender: Gender + lastName: String + maritalStatus: MaritalStatus + phone: UserPhoneInput +} + +input UpdateUserPasswordInput { + confirmNewPassword: String! + newPassword: String! + previousPassword: String! +} + +input UpdateUserTagInput { + _id: ID! + name: String! +} + +input UpdateUserTypeInput { + id: ID + userType: String +} + +scalar Upload + +type User { + _id: ID! + address: Address + appUserProfileId: AppUserProfile + birthDate: Date + createdAt: DateTime! + educationGrade: EducationGrade + email: EmailAddress! + employmentStatus: EmploymentStatus + firstName: String! + gender: Gender + image: String + joinedOrganizations: [Organization] + lastName: String! + maritalStatus: MaritalStatus + membershipRequests: [MembershipRequest] + organizationsBlockedBy: [Organization] + phone: UserPhone + pluginCreationAllowed: Boolean! + registeredEvents: [Event] + tagsAssignedWith( + after: String + before: String + first: PositiveInt + last: PositiveInt + organizationId: ID + ): UserTagsConnection + updatedAt: DateTime! +} + +type Fund { + _id: ID! + campaigns: [FundraisingCampaign!] + createdAt: DateTime! + isArchived: Boolean! + isDefault: Boolean! + name: String! + creator: User + organizationId: ID! + refrenceNumber: String + taxDeductible: Boolean! + updatedAt: DateTime! +} + +input FundWhereInput { + name_contains: String +} + +input UserAndOrganizationInput { + organizationId: ID! + userId: ID! +} + +type UserPhone { + home: PhoneNumber + mobile: PhoneNumber + work: PhoneNumber +} + +type UserConnection { + aggregate: AggregateUser! + edges: [User]! + pageInfo: PageInfo! +} + +type UserCustomData { + _id: ID! + organizationId: ID! + userId: ID! + values: JSON! +} + +type UserData { + appUserProfile: AppUserProfile! + user: User! +} + +type UserEdge { + cursor: String! + node: User! +} + +type UserFamily { + _id: ID! + admins: [User!]! + creator: User! + title: String + users: [User!]! +} + +input UserInput { + appLanguageCode: String + email: EmailAddress! + firstName: String! + lastName: String! + password: String! + selectedOrganization : ID! +} + +enum UserOrderByInput { + email_ASC + email_DESC + firstName_ASC + firstName_DESC + id_ASC + id_DESC + lastName_ASC + lastName_DESC + createdAt_ASC + createdAt_DESC +} + +type UserPhone { + home: PhoneNumber + mobile: PhoneNumber + work: PhoneNumber +} + +input UserPhoneInput { + home: PhoneNumber + mobile: PhoneNumber + work: PhoneNumber +} + +type UserTag { + _id: ID! + childTags(input: UserTagsConnectionInput!): UserTagsConnectionResult! + name: String! + organization: Organization + parentTag: UserTag + usersAssignedTo(input: UsersConnectionInput!): UsersConnectionResult! +} + +type UserTagEdge { + cursor: String! + node: UserTag! +} + +type UserTagsConnection { + edges: [UserTagEdge!]! + pageInfo: ConnectionPageInfo! +} + +input UserTagsConnectionInput { + cursor: String + direction: PaginationDirection! + limit: PositiveInt! +} + +type UserTagsConnectionResult { + data: UserTagsConnection + errors: [ConnectionError!]! +} + +enum UserType { + ADMIN + NON_USER + SUPERADMIN + USER +} + +input UserWhereInput { + email: EmailAddress + email_contains: EmailAddress + email_in: [EmailAddress!] + email_not: EmailAddress + email_not_in: [EmailAddress!] + email_starts_with: EmailAddress + event_title_contains: String + firstName: String + firstName_contains: String + firstName_in: [String!] + firstName_not: String + firstName_not_in: [String!] + firstName_starts_with: String + id: ID + id_contains: ID + id_in: [ID!] + id_not: ID + id_not_in: [ID!] + id_starts_with: ID + lastName: String + lastName_contains: String + lastName_in: [String!] + lastName_not: String + lastName_not_in: [String!] + lastName_starts_with: String +} + +type UsersConnection { + edges: [UserEdge!]! + pageInfo: ConnectionPageInfo! +} + +input UsersConnectionInput { + cursor: String + direction: PaginationDirection! + limit: PositiveInt! +} + +type UsersConnectionResult { + data: UsersConnection + errors: [ConnectionError!]! +} + +enum WeekDays { + FR + MO + SA + SU + TH + TU + WE +} + +input createChatInput { + organizationId: ID + userIds: [ID!]! +} + +input createGroupChatInput { + organizationId: ID! + title: String! + userIds: [ID!]! +} + +type Venue { + _id: ID! + capacity: Int! + description: String + imageUrl: URL + name: String! + organization: Organization! +} + +input VenueInput { + capacity: Int! + description: String + file: String + name: String! + organizationId: ID! +} + +input createUserFamilyInput { + title: String! + userIds: [ID!]! +} diff --git a/scripts/__mocks__/@dicebear/collection.ts b/scripts/__mocks__/@dicebear/collection.ts new file mode 100644 index 0000000000..9a7e1e9a57 --- /dev/null +++ b/scripts/__mocks__/@dicebear/collection.ts @@ -0,0 +1 @@ +export const initials = jest.fn(); diff --git a/scripts/__mocks__/@dicebear/core.ts b/scripts/__mocks__/@dicebear/core.ts new file mode 100644 index 0000000000..71a02f19ea --- /dev/null +++ b/scripts/__mocks__/@dicebear/core.ts @@ -0,0 +1,5 @@ +export const createAvatar = jest.fn(() => { + return { + toDataUriSync: jest.fn(() => 'mocked-data-uri'), + }; +}); diff --git a/scripts/config-overrides/custom_build.js b/scripts/config-overrides/custom_build.js new file mode 100644 index 0000000000..d5c0ce93a2 --- /dev/null +++ b/scripts/config-overrides/custom_build.js @@ -0,0 +1,17 @@ +require('dotenv').config(); +const { spawn } = require('child_process'); + +//use default react scritps config +const react_script_build = 'npx react-scripts build'; + +//use custom config overriden by react-app-rewired +const react_app_rewired_build = 'npx react-app-rewired build'; + +if (process.env.ALLOW_LOGS === "YES") { + spawn(react_app_rewired_build, { stdio: 'inherit', shell: true }); + +} +else { + spawn(react_script_build, { stdio: 'inherit', shell: true }); +} + diff --git a/scripts/config-overrides/custom_start.js b/scripts/config-overrides/custom_start.js new file mode 100644 index 0000000000..a784f1bb48 --- /dev/null +++ b/scripts/config-overrides/custom_start.js @@ -0,0 +1,19 @@ +require('dotenv').config(); +const { spawn } = require('child_process'); + +const port = process.env.PORT || 4321; +process.env.PORT = port; + +const react_script_start = 'npx react-scripts start'; +const react_app_rewired_start = 'npx react-app-rewired start --config-overrides=scripts/config-overrides'; + +if (process.env.ALLOW_LOGS === "YES") { + // Execute the npm command + spawn(react_app_rewired_start, { stdio: 'inherit', shell: true }); + +} +else { + // Execute the npm command + spawn(react_script_start, { stdio: 'inherit', shell: true }); + } + diff --git a/scripts/config-overrides/index.js b/scripts/config-overrides/index.js new file mode 100644 index 0000000000..a8d16aa7e9 --- /dev/null +++ b/scripts/config-overrides/index.js @@ -0,0 +1,29 @@ +const { override, addWebpackPlugin } = require('customize-cra'); +const webpack = require('webpack'); + + +module.exports = override( + // Add your new webpack plugin + addWebpackPlugin(new webpack.ProgressPlugin({ + activeModules: true, + entries: true, + handler: (percentage, message, ...args) => { + // Log a custom progress message with active module and its count + console.info(`: ${Math.floor(percentage * 100)}% ${message}`); + }, + modules: true, + modulesCount: 5000, + profile: false, + dependencies: true, + dependenciesCount: 10000, + percentBy: null, +})), + + // Modify infrastructureLogging level + (config) => { + config.infrastructureLogging = { + level: 'verbose', + }; + return config; + } +); \ No newline at end of file diff --git a/scripts/config-overrides/package.json b/scripts/config-overrides/package.json new file mode 100644 index 0000000000..c0a38b857f --- /dev/null +++ b/scripts/config-overrides/package.json @@ -0,0 +1,5 @@ +{ + "name": "config-overrides", + "version": "1.0.0", + "type": "commonjs" +} diff --git a/scripts/custom-test-env.js b/scripts/custom-test-env.js new file mode 100644 index 0000000000..6174d8cf11 --- /dev/null +++ b/scripts/custom-test-env.js @@ -0,0 +1,16 @@ +import Environment from 'jest-environment-jsdom'; +import { TextEncoder, TextDecoder } from 'util'; + +/** + * A custom environment to set the TextEncoder and TextDecoder variables, that is required by @pdfme during testing. + * Providing a polyfill to the environment for the same + */ +export default class CustomTestEnvironment extends Environment { + async setup() { + await super.setup(); + if (typeof this.global.TextEncoder === 'undefined') { + this.global.TextEncoder = TextEncoder; + this.global.TextDecoder = TextDecoder; + } + } +} diff --git a/scripts/githooks/check-localstorage-usage.js b/scripts/githooks/check-localstorage-usage.js new file mode 100755 index 0000000000..0a811df307 --- /dev/null +++ b/scripts/githooks/check-localstorage-usage.js @@ -0,0 +1,96 @@ +#!/usr/bin/env node + +import { readFileSync, existsSync } from 'fs'; +import path from 'path'; +import { execSync } from 'child_process'; + +const args = process.argv.slice(2); +const scanEntireRepo = args.includes('--scan-entire-repo'); + +const containsSkipComment = (file) => { + try { + const content = readFileSync(file, 'utf-8'); + return content.includes('// SKIP_LOCALSTORAGE_CHECK'); + } catch (error) { + console.error(`Error reading file ${file}:`, error.message); + return false; + } +}; + +const getModifiedFiles = () => { + try { + if (scanEntireRepo) { + const result = execSync('git ls-files | grep ".tsx\\?$"', { + encoding: 'utf-8', + }); + return result.trim().split('\n'); + } + + const result = execSync('git diff --cached --name-only', { + encoding: 'utf-8', + }); + return result.trim().split('\n'); + } catch (error) { + console.error('Error fetching modified files:', error.message); + process.exit(1); + } +}; + +const files = getModifiedFiles(); + +const filesWithLocalStorage = []; + +const checkLocalStorageUsage = (file) => { + if (!file) { + return; + } + + const fileName = path.basename(file); + + // Skip files with specific names or containing a skip comment + if ( + fileName === 'check-localstorage-usage.js' || + fileName === 'useLocalstorage.test.ts' || + fileName === 'useLocalstorage.ts' || + containsSkipComment(file) + ) { + console.log(`Skipping file: ${file}`); + return; + } + + try { + if (existsSync(file)) { + const content = readFileSync(file, 'utf-8'); + + if ( + content.includes('localStorage.getItem') || + content.includes('localStorage.setItem') || + content.includes('localStorage.removeItem') + ) { + filesWithLocalStorage.push(file); + } + } else { + console.log(`File ${file} does not exist.`); + } + } catch (error) { + console.error(`Error reading file ${file}:`, error.message); + } +}; + +files.forEach(checkLocalStorageUsage); + +if (filesWithLocalStorage.length > 0) { + console.error('\x1b[31m%s\x1b[0m', '\nError: Found usage of localStorage'); + console.error('\nFiles with localStorage usage:'); + filesWithLocalStorage.forEach((file) => console.error(file)); + + console.info( + '\x1b[34m%s\x1b[0m', + '\nInfo: Consider using custom hook functions.' + ); + console.info( + 'Please use the getItem, setItem, and removeItem functions provided by the custom hook useLocalStorage.\n' + ); + + process.exit(1); +} diff --git a/scripts/githooks/update-toc.js b/scripts/githooks/update-toc.js new file mode 100644 index 0000000000..268becfd13 --- /dev/null +++ b/scripts/githooks/update-toc.js @@ -0,0 +1,14 @@ +import fs from 'fs'; +import { execSync } from 'child_process'; + +const markdownFiles = fs + .readdirSync('./') + .filter((file) => file.endsWith('.md')); + +markdownFiles.forEach((file) => { + const command = `markdown-toc -i "${file}" --bullets "-"`; + execSync(command, { stdio: 'inherit' }); + +}); + +console.log('Table of contents updated successfully.'); diff --git a/scripts/test.js b/scripts/test.js new file mode 100644 index 0000000000..e5858251ff --- /dev/null +++ b/scripts/test.js @@ -0,0 +1,52 @@ +'use strict'; + +// Do this as the first thing so that any code reading it knows the right env. +process.env.BABEL_ENV = 'test'; +process.env.NODE_ENV = 'test'; +process.env.PUBLIC_URL = ''; + +// Makes the script crash on unhandled rejections instead of silently +// ignoring them. In the future, promise rejections that are not handled will +// terminate the Node.js process with a non-zero exit code. +process.on('unhandledRejection', (err) => { + throw err; +}); + +// Ensure environment variables are read. +import 'react-scripts/config/env.js'; + +import jest from 'jest'; +import { execSync } from 'child_process'; + +const argv = process.argv.slice(2); + +function isInGitRepository() { + try { + execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' }); + return true; + } catch (e) { + return false; + } +} + +function isInMercurialRepository() { + try { + execSync('hg --cwd . root', { stdio: 'ignore' }); + return true; + } catch (e) { + return false; + } +} + +// Watch unless on CI or explicitly running all tests +if ( + !process.env.CI && + argv.indexOf('--watchAll') === -1 && + argv.indexOf('--watchAll=false') === -1 +) { + // https://github.com/facebook/create-react-app/issues/5210 + const hasSourceControl = isInGitRepository() || isInMercurialRepository(); + argv.push(hasSourceControl ? '--watch' : '--watchAll'); +} + +jest.run(argv); diff --git a/setup.ts b/setup.ts new file mode 100644 index 0000000000..f930acc13a --- /dev/null +++ b/setup.ts @@ -0,0 +1,177 @@ +import dotenv from 'dotenv'; +import fs from 'fs'; +import inquirer from 'inquirer'; +import { checkConnection } from './src/setup/checkConnection/checkConnection'; +import { askForTalawaApiUrl } from './src/setup/askForTalawaApiUrl/askForTalawaApiUrl'; +import { checkEnvFile } from './src/setup/checkEnvFile/checkEnvFile'; +import { validateRecaptcha } from './src/setup/validateRecaptcha/validateRecaptcha'; +import { askForCustomPort } from './src/setup/askForCustomPort/askForCustomPort'; + +export async function main(): Promise { + console.log('Welcome to the Talawa Admin setup! 🚀'); + + if (!fs.existsSync('.env')) { + fs.openSync('.env', 'w'); + const config = dotenv.parse(fs.readFileSync('.env.example')); + for (const key in config) { + fs.appendFileSync('.env', `${key}=${config[key]}\n`); + } + } else { + checkEnvFile(); + } + + let shouldSetCustomPort: boolean; + + if (process.env.PORT) { + console.log( + `\nCustom port for development server already exists with the value:\n${process.env.PORT}`, + ); + shouldSetCustomPort = true; + } else { + const { shouldSetCustomPortResponse } = await inquirer.prompt({ + type: 'confirm', + name: 'shouldSetCustomPortResponse', + message: 'Would you like to set up a custom port?', + default: true, + }); + shouldSetCustomPort = shouldSetCustomPortResponse; + } + + if (shouldSetCustomPort) { + const customPort = await askForCustomPort(); + + const port = dotenv.parse(fs.readFileSync('.env')).PORT; + + fs.readFile('.env', 'utf8', (err, data) => { + const result = data.replace(`PORT=${port}`, `PORT=${customPort}`); + fs.writeFileSync('.env', result, 'utf8'); + }); + } + + let shouldSetTalawaApiUrl: boolean; + + if (process.env.REACT_APP_TALAWA_URL) { + console.log( + `\nEndpoint for accessing talawa-api graphql service already exists with the value:\n${process.env.REACT_APP_TALAWA_URL}`, + ); + shouldSetTalawaApiUrl = true; + } else { + const { shouldSetTalawaApiUrlResponse } = await inquirer.prompt({ + type: 'confirm', + name: 'shouldSetTalawaApiUrlResponse', + message: 'Would you like to set up talawa-api endpoint?', + default: true, + }); + shouldSetTalawaApiUrl = shouldSetTalawaApiUrlResponse; + } + + if (shouldSetTalawaApiUrl) { + let isConnected = false, + endpoint = ''; + + while (!isConnected) { + endpoint = await askForTalawaApiUrl(); + const url = new URL(endpoint); + isConnected = await checkConnection(url.origin); + } + + const talawaApiUrl = dotenv.parse( + fs.readFileSync('.env'), + ).REACT_APP_TALAWA_URL; + + 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'); + }); + } + + const { shouldUseRecaptcha } = await inquirer.prompt({ + type: 'confirm', + name: 'shouldUseRecaptcha', + message: 'Would you like to set up ReCAPTCHA?', + default: true, + }); + + if (shouldUseRecaptcha) { + const useRecaptcha = dotenv.parse( + fs.readFileSync('.env'), + ).REACT_APP_USE_RECAPTCHA; + + fs.readFile('.env', 'utf8', (err, data) => { + const result = data.replace( + `REACT_APP_USE_RECAPTCHA=${useRecaptcha}`, + `REACT_APP_USE_RECAPTCHA=yes`, + ); + fs.writeFileSync('.env', result, 'utf8'); + }); + let shouldSetRecaptchaSiteKey: boolean; + if (process.env.REACT_APP_RECAPTCHA_SITE_KEY) { + console.log( + `\nreCAPTCHA site key already exists with the value ${process.env.REACT_APP_RECAPTCHA_SITE_KEY}`, + ); + shouldSetRecaptchaSiteKey = true; + } else { + const { shouldSetRecaptchaSiteKeyResponse } = await inquirer.prompt({ + type: 'confirm', + name: 'shouldSetRecaptchaSiteKeyResponse', + message: 'Would you like to set up a reCAPTCHA site key?', + default: true, + }); + shouldSetRecaptchaSiteKey = shouldSetRecaptchaSiteKeyResponse; + } + + if (shouldSetRecaptchaSiteKey) { + const { recaptchaSiteKeyInput } = await inquirer.prompt([ + { + type: 'input', + name: 'recaptchaSiteKeyInput', + message: 'Enter your reCAPTCHA site key:', + validate: async (input: string): Promise => { + if (validateRecaptcha(input)) { + return true; + } + return 'Invalid reCAPTCHA site key. Please try again.'; + }, + }, + ]); + + const recaptchaSiteKey = dotenv.parse( + fs.readFileSync('.env'), + ).REACT_APP_RECAPTCHA_SITE_KEY; + + fs.readFile('.env', 'utf8', (err, data) => { + const result = data.replace( + `REACT_APP_RECAPTCHA_SITE_KEY=${recaptchaSiteKey}`, + `REACT_APP_RECAPTCHA_SITE_KEY=${recaptchaSiteKeyInput}`, + ); + fs.writeFileSync('.env', result, 'utf8'); + }); + } + } + + const { shouldLogErrors } = await inquirer.prompt({ + type: 'confirm', + name: 'shouldLogErrors', + message: + 'Would you like to log Compiletime and Runtime errors in the console?', + default: true, + }); + + if (shouldLogErrors) { + const logErrors = dotenv.parse(fs.readFileSync('.env')).ALLOW_LOGS; + + fs.readFile('.env', 'utf8', (err, data) => { + const result = data.replace(`ALLOW_LOGS=${logErrors}`, 'ALLOW_LOGS=YES'); + fs.writeFileSync('.env', result, 'utf8'); + }); + } + + console.log( + '\nCongratulations! Talawa Admin has been successfully setup! 🥂🎉', + ); +} + +main(); diff --git a/src/App.test.tsx b/src/App.test.tsx index 2a68616d98..3146066e26 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -1,9 +1,111 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { act, render, screen } from '@testing-library/react'; +import { Provider } from 'react-redux'; +import { MockedProvider } from '@apollo/react-testing'; +import { BrowserRouter } from 'react-router-dom'; +import { I18nextProvider } from 'react-i18next'; +import 'jest-location-mock'; import App from './App'; +import { store } from 'state/store'; +import { CHECK_AUTH } from 'GraphQl/Queries/Queries'; +import i18nForTest from './utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import useLocalStorage from 'utils/useLocalstorage'; -test('renders learn react link', () => { - render(); - const linkElement = screen.getByText(/learn react/i); - expect(linkElement).toBeInTheDocument(); +const { setItem } = useLocalStorage(); + +// Mock the modules for PieChart rendering as they require a trasformer being used (which is not done by Jest) +// These modules are used by the Feedback components +jest.mock('@mui/x-charts/PieChart', () => ({ + pieArcLabelClasses: jest.fn(), + PieChart: jest.fn().mockImplementation(() => <>Test), + pieArcClasses: jest.fn(), +})); + +const MOCKS = [ + { + request: { + query: CHECK_AUTH, + }, + result: { + data: { + checkAuth: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + createdAt: '2023-04-13T04:53:17.742+00:00', + image: 'john.jpg', + email: 'johndoe@gmail.com', + birthDate: '1990-01-01', + educationGrade: 'NO_GRADE', + employmentStatus: 'EMPLOYED', + gender: 'MALE', + maritalStatus: 'SINGLE', + address: { + line1: 'line1', + state: 'state', + countryCode: 'IND', + }, + phone: { + mobile: '+8912313112', + }, + }, + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink([], true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +describe('Testing the App Component', () => { + test('Component should be rendered properly and user is loggedin', async () => { + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); + render( + + + + + + + + + , + ); + + await wait(); + + window.location.assign('/orglist'); + await wait(); + expect(window.location).toBeAt('/orglist'); + expect( + screen.getByText( + 'An open source application by Palisadoes Foundation volunteers', + ), + ).toBeTruthy(); + }); + + test('Component should be rendered properly and user is loggedout', async () => { + render( + + + + + + + + + , + ); + + await wait(); + }); }); diff --git a/src/App.tsx b/src/App.tsx index c31b4f754d..7ee6ba72cb 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,27 +1,189 @@ -import React from 'react'; -import './App.css'; +import AddOnStore from 'components/AddOn/core/AddOnStore/AddOnStore'; +import OrganizationScreen from 'components/OrganizationScreen/OrganizationScreen'; +import SecuredRoute from 'components/SecuredRoute/SecuredRoute'; +import SuperAdminScreen from 'components/SuperAdminScreen/SuperAdminScreen'; +import * as installedPlugins from 'components/plugins/index'; +import { Route, Routes } from 'react-router-dom'; +import BlockUser from 'screens/BlockUser/BlockUser'; +import EventManagement from 'screens/EventManagement/EventManagement'; +import ForgotPassword from 'screens/ForgotPassword/ForgotPassword'; +import LoginPage from 'screens/LoginPage/LoginPage'; +import MemberDetail from 'screens/MemberDetail/MemberDetail'; +import OrgContribution from 'screens/OrgContribution/OrgContribution'; +import OrgList from 'screens/OrgList/OrgList'; +import OrgPost from 'screens/OrgPost/OrgPost'; +import OrgSettings from 'screens/OrgSettings/OrgSettings'; +import OrganizationActionItems from 'screens/OrganizationActionItems/OrganizationActionItems'; +import OrganizationAgendaCategory from 'screens/OrganizationAgendaCategory/OrganizationAgendaCategory'; +import OrganizationDashboard from 'screens/OrganizationDashboard/OrganizationDashboard'; +import OrganizationEvents from 'screens/OrganizationEvents/OrganizationEvents'; +import OrganizaitionFundCampiagn from 'screens/OrganizationFundCampaign/OrganizationFundCampagins'; +import OrganizationFunds from 'screens/OrganizationFunds/OrganizationFunds'; +import OrganizationPeople from 'screens/OrganizationPeople/OrganizationPeople'; +import PageNotFound from 'screens/PageNotFound/PageNotFound'; +import Requests from 'screens/Requests/Requests'; +import Users from 'screens/Users/Users'; +import CommunityProfile from 'screens/CommunityProfile/CommunityProfile'; +import OrganizationVenues from 'screens/OrganizationVenues/OrganizationVenues'; -function App(): JSX.Element { - return ( -
-
-
- -

- Edit src/App.js and save to reload. -

- - Learn React - -
-
+import React, { useEffect } from 'react'; +// User Portal Components +import Donate from 'screens/UserPortal/Donate/Donate'; +import Events from 'screens/UserPortal/Events/Events'; +import Posts from 'screens/UserPortal/Posts/Posts'; +import Organizations from 'screens/UserPortal/Organizations/Organizations'; +import People from 'screens/UserPortal/People/People'; +import Settings from 'screens/UserPortal/Settings/Settings'; +// import UserLoginPage from 'screens/UserPortal/UserLoginPage/UserLoginPage'; +import Chat from 'screens/UserPortal/Chat/Chat'; +import { 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'; + +const { setItem } = useLocalStorage(); + +function app(): JSX.Element { + /*const { updatePluginLinks, updateInstalled } = bindActionCreators( + actionCreators, + dispatch + ); + + const getInstalledPlugins = async () => { + const plugins = await fetchInstalled(); + updateInstalled(plugins); + updatePluginLinks(new PluginHelper().generateLinks(plugins)); + }; + + const fetchInstalled = async () => { + const result = await fetch(`http://localhost:3005/installed`); + return await result.json(); + }; + + useEffect(() => { + getInstalledPlugins(); + }, []);*/ + + // const appRoutes = useSelector((state: RootState) => state.appRoutes); + // const { components } = appRoutes; + + // TODO: Fetch Installed plugin extras and store for use within MainContent and Side Panel Components. + + const { data, loading } = useQuery(CHECK_AUTH); + + useEffect(() => { + if (data) { + setItem('name', `${data.checkAuth.firstName} ${data.checkAuth.lastName}`); + setItem('id', data.checkAuth._id); + setItem('email', data.checkAuth.email); + setItem('IsLoggedIn', 'TRUE'); + setItem('FirstName', data.checkAuth.firstName); + setItem('LastName', data.checkAuth.lastName); + setItem('UserImage', data.checkAuth.image); + setItem('Email', data.checkAuth.email); + } + }, [data, loading]); + + const extraRoutes = Object.entries(installedPlugins).map( + ( + plugin: [ + string, + ( + | typeof installedPlugins.DummyPlugin + | typeof installedPlugins.DummyPlugin2 + ), + ], + index: number, + ) => { + const extraComponent = plugin[1]; + return ( + ); -
+ }, + ); + + return ( + <> + + } /> + }> + }> + } /> + } /> + } /> + } /> + + }> + } /> + } /> + } /> + } /> + } /> + } + /> + } + /> + } + /> + } /> + } + /> + } + /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + {extraRoutes} + + + } /> + {/* User Portal Routes */} + }> + } /> + } /> + } /> + }> + } /> + } /> + } /> + } /> + } /> + }> + } + /> + + + + {/* */} + } /> + + ); } -export default App; +export default app; diff --git a/src/Constant/constant.spec.ts b/src/Constant/constant.spec.ts new file mode 100644 index 0000000000..c2e57d29df --- /dev/null +++ b/src/Constant/constant.spec.ts @@ -0,0 +1,29 @@ +import { + AUTH_TOKEN, + BACKEND_URL, + RECAPTCHA_SITE_KEY, + REACT_APP_USE_RECAPTCHA, +} from './constant'; + +describe('constants', () => { + it('AUTH_TOKEN should be an empty string', () => { + expect(typeof AUTH_TOKEN).toEqual('string'); + expect(AUTH_TOKEN).toEqual(''); + }); + + it('BACKEND_URL should be equal to REACT_APP_TALAWA_URL environment variable', () => { + expect(BACKEND_URL).toEqual(process.env.REACT_APP_TALAWA_URL); + }); + + it('RECAPTCHA_SITE_KEY should be equal to REACT_APP_RECAPTCHA_SITE_KEY environment variable', () => { + expect(RECAPTCHA_SITE_KEY).toEqual( + process.env.REACT_APP_RECAPTCHA_SITE_KEY, + ); + }); + + it('REACT_APP_USE_RECAPTCHA should be equal to REACT_APP_USE_RECAPTCHA environment variable', () => { + expect(REACT_APP_USE_RECAPTCHA).toEqual( + process.env.REACT_APP_USE_RECAPTCHA, + ); + }); +}); diff --git a/src/Constant/constant.ts b/src/Constant/constant.ts new file mode 100644 index 0000000000..d3b0efe1c1 --- /dev/null +++ b/src/Constant/constant.ts @@ -0,0 +1,7 @@ +export const AUTH_TOKEN = ''; +export const BACKEND_URL = process.env.REACT_APP_TALAWA_URL; +export const RECAPTCHA_SITE_KEY = process.env.REACT_APP_RECAPTCHA_SITE_KEY; +export const REACT_APP_USE_RECAPTCHA = process.env.REACT_APP_USE_RECAPTCHA; +export const REACT_APP_CUSTOM_PORT = process.env.PORT; +export const REACT_APP_BACKEND_WEBSOCKET_URL: string = + process.env.REACT_APP_BACKEND_WEBSOCKET_URL || ''; diff --git a/src/GraphQl/Mutations/ActionItemCategoryMutations.ts b/src/GraphQl/Mutations/ActionItemCategoryMutations.ts new file mode 100644 index 0000000000..daae836362 --- /dev/null +++ b/src/GraphQl/Mutations/ActionItemCategoryMutations.ts @@ -0,0 +1,39 @@ +import gql from 'graphql-tag'; + +/** + * GraphQL mutation to create an action item category. + * + * @param name - Name of the ActionItemCategory. + * @param organizationId - Organization to which the ActionItemCategory belongs. + */ + +export const CREATE_ACTION_ITEM_CATEGORY_MUTATION = gql` + mutation CreateActionItemCategory($name: String!, $organizationId: ID!) { + createActionItemCategory(name: $name, organizationId: $organizationId) { + _id + } + } +`; + +/** + * GraphQL mutation to update an action item category. + * + * @param id - The id of the ActionItemCategory to be updated. + * @param name - Updated name of the ActionItemCategory. + * @param isDisabled - Updated disabled status of the ActionItemCategory. + */ + +export const UPDATE_ACTION_ITEM_CATEGORY_MUTATION = gql` + mutation UpdateActionItemCategory( + $actionItemCategoryId: ID! + $name: String + $isDisabled: Boolean + ) { + updateActionItemCategory( + id: $actionItemCategoryId + data: { name: $name, isDisabled: $isDisabled } + ) { + _id + } + } +`; diff --git a/src/GraphQl/Mutations/ActionItemMutations.ts b/src/GraphQl/Mutations/ActionItemMutations.ts new file mode 100644 index 0000000000..58dc7756d3 --- /dev/null +++ b/src/GraphQl/Mutations/ActionItemMutations.ts @@ -0,0 +1,85 @@ +import gql from 'graphql-tag'; + +/** + * GraphQL mutation to create an action item. + * + * @param actionItemCategoryId - ActionItemCategory to which the ActionItem is related. + * @param assigneeId - User to whom the ActionItem is assigned. + * @param preCompletionNotes - Notes prior to completion. + * @param dueDate - Due date. + * @param eventId - Event to which the ActionItem is related. + */ + +export const CREATE_ACTION_ITEM_MUTATION = gql` + mutation CreateActionItem( + $actionItemCategoryId: ID! + $assigneeId: ID! + $preCompletionNotes: String + $dueDate: Date + $eventId: ID + ) { + createActionItem( + actionItemCategoryId: $actionItemCategoryId + data: { + assigneeId: $assigneeId + preCompletionNotes: $preCompletionNotes + dueDate: $dueDate + eventId: $eventId + } + ) { + _id + } + } +`; + +/** + * GraphQL mutation to update an action item. + * + * @param id - Id of the ActionItem to be updated. + * @param assigneeId - User to whom the ActionItem is assigned. + * @param preCompletionNotes - Notes prior to completion. + * @param postCompletionNotes - Notes on completion. + * @param dueDate - Due date. + * @param completionDate - Completion date. + * @param isCompleted - Whether the ActionItem has been completed. + */ + +export const UPDATE_ACTION_ITEM_MUTATION = gql` + mutation UpdateActionItem( + $actionItemId: ID! + $assigneeId: ID! + $preCompletionNotes: String + $postCompletionNotes: String + $dueDate: Date + $completionDate: Date + $isCompleted: Boolean + ) { + updateActionItem( + id: $actionItemId + data: { + assigneeId: $assigneeId + preCompletionNotes: $preCompletionNotes + postCompletionNotes: $postCompletionNotes + dueDate: $dueDate + completionDate: $completionDate + isCompleted: $isCompleted + } + ) { + _id + } + } +`; + +/** + * GraphQL mutation to delete an action item. + * + * @param id - Id of the ActionItem to be updated. + */ + +export const DELETE_ACTION_ITEM_MUTATION = gql` + mutation RemoveActionItem($actionItemId: ID!) { + removeActionItem(id: $actionItemId) { + _id + } + } +`; diff --git a/src/GraphQl/Mutations/AgendaCategoryMutations.ts b/src/GraphQl/Mutations/AgendaCategoryMutations.ts new file mode 100644 index 0000000000..c344eca7e2 --- /dev/null +++ b/src/GraphQl/Mutations/AgendaCategoryMutations.ts @@ -0,0 +1,45 @@ +import gql from 'graphql-tag'; + +/** + * GraphQL mutation to create an agenda category. + * + * @param input - Name, Description, OrganizationID of the AgendaCategory. + */ + +export const CREATE_AGENDA_ITEM_CATEGORY_MUTATION = gql` + mutation CreateAgendaCategory($input: CreateAgendaCategoryInput!) { + createAgendaCategory(input: $input) { + _id + } + } +`; + +/** + * GraphQL mutation to delete an agenda category. + * + * @param deleteAgendaCategoryId - The ID of the AgendaCategory to be deleted. + */ + +export const DELETE_AGENDA_ITEM_CATEGORY_MUTATION = gql` + mutation DeleteAgendaCategory($deleteAgendaCategoryId: ID!) { + deleteAgendaCategory(id: $deleteAgendaCategoryId) + } +`; + +/** + * GraphQL mutation to update an agenda category. + * + * @param updateAgendaCategoryId - The ID of the AgendaCategory to be updated. + * @param input - Updated Name, Description, OrganizationID of the AgendaCategory. + */ + +export const UPDATE_AGENDA_ITEM_CATEGORY_MUTATION = gql` + mutation UpdateAgendaCategory( + $updateAgendaCategoryId: ID! + $input: UpdateAgendaCategoryInput! + ) { + updateAgendaCategory(id: $updateAgendaCategoryId, input: $input) { + _id + } + } +`; diff --git a/src/GraphQl/Mutations/AgendaItemMutations.ts b/src/GraphQl/Mutations/AgendaItemMutations.ts new file mode 100644 index 0000000000..20191b1b7c --- /dev/null +++ b/src/GraphQl/Mutations/AgendaItemMutations.ts @@ -0,0 +1,31 @@ +import gql from 'graphql-tag'; + +export const CREATE_AGENDA_ITEM_MUTATION = gql` + mutation CreateAgendaItem($input: CreateAgendaItemInput!) { + createAgendaItem(input: $input) { + _id + title + } + } +`; + +export const DELETE_AGENDA_ITEM_MUTATION = gql` + mutation RemoveAgendaItem($removeAgendaItemId: ID!) { + removeAgendaItem(id: $removeAgendaItemId) { + _id + } + } +`; + +export const UPDATE_AGENDA_ITEM_MUTATION = gql` + mutation UpdateAgendaItem( + $updateAgendaItemId: ID! + $input: UpdateAgendaItemInput! + ) { + updateAgendaItem(id: $updateAgendaItemId, input: $input) { + _id + description + title + } + } +`; diff --git a/src/GraphQl/Mutations/CampaignMutation.ts b/src/GraphQl/Mutations/CampaignMutation.ts new file mode 100644 index 0000000000..c012141dc8 --- /dev/null +++ b/src/GraphQl/Mutations/CampaignMutation.ts @@ -0,0 +1,87 @@ +import gql from 'graphql-tag'; + +/** + * GraphQL mutation to create a new fund Campaign. + * + * @param name - The name of the fund. + * @param fundId - The fund ID the campaign is associated with. + * @param fundingGoal - The funding goal of the campaign. + * @param startDate - The start date of the campaign. + * @param endDate - The end date of the campaign. + * @param currency - The currency of the campaign. + * @returns The ID of the created campaign. + */ + +export const CREATE_CAMPAIGN_MUTATION = gql` + mutation createFundraisingCampaign( + $fundId: ID! + $name: String! + $fundingGoal: Float! + $startDate: Date! + $endDate: Date! + $currency: Currency! + ) { + createFundraisingCampaign( + data: { + fundId: $fundId + name: $name + fundingGoal: $fundingGoal + startDate: $startDate + endDate: $endDate + currency: $currency + } + ) { + _id + } + } +`; + +/** + * GraphQL mutation to update a fund Campaign. + * + * @param id - The ID of the campaign being updated. + * @param name - The name of the campaign. + * @param fundingGoal - The funding goal of the campaign. + * @param startDate - The start date of the campaign. + * @param endDate - The end date of the campaign. + * @param currency - The currency of the campaign. + * @returns The ID of the updated campaign. + */ + +export const UPDATE_CAMPAIGN_MUTATION = gql` + mutation updateFundraisingCampaign( + $id: ID! + $name: String + $fundingGoal: Float + $startDate: Date + $endDate: Date + $currency: Currency + ) { + updateFundraisingCampaign( + id: $id + data: { + name: $name + fundingGoal: $fundingGoal + startDate: $startDate + endDate: $endDate + currency: $currency + } + ) { + _id + } + } +`; + +/** + * GraphQL mutation to delete a fund Campaign. + * + * @param id - The ID of the campaign being deleted. + * @returns The ID of the deleted campaign. + */ +export const DELETE_CAMPAIGN_MUTATION = gql` + mutation removeFundraisingCampaign($id: ID!) { + removeFundraisingCampaign(id: $id) { + _id + } + } +`; diff --git a/src/GraphQl/Mutations/CommentMutations.ts b/src/GraphQl/Mutations/CommentMutations.ts new file mode 100644 index 0000000000..7a2ca00c83 --- /dev/null +++ b/src/GraphQl/Mutations/CommentMutations.ts @@ -0,0 +1,58 @@ +import gql from 'graphql-tag'; + +/** + * GraphQL mutation to create a new comment on a post. + * + * @param comment - The text content of the comment. + * @param postId - The ID of the post to which the comment is being added. + * @returns The created comment object. + */ + +export const CREATE_COMMENT_POST = gql` + mutation createComment($comment: String!, $postId: ID!) { + createComment(data: { text: $comment }, postId: $postId) { + _id + creator { + _id + firstName + lastName + email + } + likeCount + likedBy { + _id + } + text + } + } +`; + +/** + * GraphQL mutation to like a comment. + * + * @param commentId - The ID of the comment to be liked. + * @returns The liked comment object. + */ + +export const LIKE_COMMENT = gql` + mutation likeComment($commentId: ID!) { + likeComment(id: $commentId) { + _id + } + } +`; + +/** + * GraphQL mutation to unlike a comment. + * + * @param commentId - The ID of the comment to be unliked. + * @returns The unliked comment object. + */ + +export const UNLIKE_COMMENT = gql` + mutation unlikeComment($commentId: ID!) { + unlikeComment(id: $commentId) { + _id + } + } +`; diff --git a/src/GraphQl/Mutations/EventAttendeeMutations.ts b/src/GraphQl/Mutations/EventAttendeeMutations.ts new file mode 100644 index 0000000000..94d7d97705 --- /dev/null +++ b/src/GraphQl/Mutations/EventAttendeeMutations.ts @@ -0,0 +1,49 @@ +import gql from 'graphql-tag'; + +/** + * GraphQL mutation to add an attendee to an event. + * + * @param userId - The ID of the user being added as an attendee. + * @param eventId - The ID of the event to which the user is being added as an attendee. + * @returns The updated event object with the added attendee. + */ + +export const ADD_EVENT_ATTENDEE = gql` + mutation addEventAttendee($userId: ID!, $eventId: ID!) { + addEventAttendee(data: { userId: $userId, eventId: $eventId }) { + _id + } + } +`; + +/** + * GraphQL mutation to remove an attendee from an event. + * + * @param userId - The ID of the user being removed as an attendee. + * @param eventId - The ID of the event from which the user is being removed as an attendee. + * @returns The updated event object without the removed attendee. + */ + +export const REMOVE_EVENT_ATTENDEE = gql` + mutation removeEventAttendee($userId: ID!, $eventId: ID!) { + removeEventAttendee(data: { userId: $userId, eventId: $eventId }) { + _id + } + } +`; + +/** + * GraphQL mutation to mark a user's check-in at an event. + * + * @param userId - The ID of the user checking in. + * @param eventId - The ID of the event at which the user is checking in. + * @returns The updated event object with the user's check-in information. + */ + +export const MARK_CHECKIN = gql` + mutation checkIn($userId: ID!, $eventId: ID!) { + checkIn(data: { userId: $userId, eventId: $eventId }) { + _id + } + } +`; diff --git a/src/GraphQl/Mutations/FundMutation.ts b/src/GraphQl/Mutations/FundMutation.ts new file mode 100644 index 0000000000..45bdc05e96 --- /dev/null +++ b/src/GraphQl/Mutations/FundMutation.ts @@ -0,0 +1,85 @@ +import gql from 'graphql-tag'; + +/** + * GraphQL mutation to create a new fund. + * + * @param name - The name of the fund. + * @param organizationId - The organization ID the fund is associated with. + * @param refrenceNumber - The reference number of the fund. + * @param taxDeductible - Whether the fund is tax deductible. + * @param isArchived - Whether the fund is archived. + * @param isDefault - Whether the fund is the default. + * @returns The ID of the created fund. + */ +export const CREATE_FUND_MUTATION = gql` + mutation CreateFund( + $name: String! + $organizationId: ID! + $refrenceNumber: String + $taxDeductible: Boolean! + $isArchived: Boolean! + $isDefault: Boolean! + ) { + createFund( + data: { + name: $name + organizationId: $organizationId + refrenceNumber: $refrenceNumber + taxDeductible: $taxDeductible + isArchived: $isArchived + isDefault: $isDefault + } + ) { + _id + } + } +`; + +/** + * GraphQL mutation to update a fund. + * + * @param id - The ID of the fund being updated. + * @param name - The name of the fund. + * @param refrenceNumber - The reference number of the fund. + * @param taxDeductible - Whether the fund is tax deductible. + * @param isArchived - Whether the fund is archived. + * @param isDefault - Whether the fund is the default. + * @returns The ID of the updated fund. + */ +export const UPDATE_FUND_MUTATION = gql` + mutation UpdateFund( + $id: ID! + $name: String + $refrenceNumber: String + $taxDeductible: Boolean + $isArchived: Boolean + $isDefault: Boolean + ) { + updateFund( + id: $id + data: { + name: $name + refrenceNumber: $refrenceNumber + taxDeductible: $taxDeductible + isArchived: $isArchived + isDefault: $isDefault + } + ) { + _id + } + } +`; + +/** + * GraphQL mutation to remove a fund. + * + * @param id - The ID of the fund being removed. + * @returns The ID of the removed fund. + */ +export const REMOVE_FUND_MUTATION = gql` + mutation RemoveFund($id: ID!) { + removeFund(id: $id) { + _id + } + } +`; diff --git a/src/GraphQl/Mutations/OrganizationMutations.ts b/src/GraphQl/Mutations/OrganizationMutations.ts new file mode 100644 index 0000000000..b61d70607b --- /dev/null +++ b/src/GraphQl/Mutations/OrganizationMutations.ts @@ -0,0 +1,292 @@ +import gql from 'graphql-tag'; + +// Changes the role of a user in an organization +/** + * GraphQL mutation to update the role of a user in an organization. + * + * @param organizationId - The ID of the organization in which the user's role is being updated. + * @param userId - The ID of the user whose role is being updated. + * @param role - The new role to be assigned to the user in the organization. + * @returns The updated user object with the new role in the organization. + */ +export const UPDATE_USER_ROLE_IN_ORG_MUTATION = gql` + mutation updateUserRoleInOrganization( + $organizationId: ID! + $userId: ID! + $role: String! + ) { + updateUserRoleInOrganization( + organizationId: $organizationId + userId: $userId + role: $role + ) { + _id + } + } +`; + +/** + * GraphQL mutation to create a sample organization. + * + * @returns The created sample organization object. + */ + +export const CREATE_SAMPLE_ORGANIZATION_MUTATION = gql` + mutation { + createSampleOrganization + } +`; + +/** + * GraphQL mutation to remove a sample organization. + * + * @returns The removed sample organization object. + */ + +export const REMOVE_SAMPLE_ORGANIZATION_MUTATION = gql` + mutation { + removeSampleOrganization + } +`; + +/** + * GraphQL mutation to create a direct chat between users in an organization. + * + * @param userIds - An array of user IDs participating in the direct chat. + * @param organizationId - The ID of the organization where the direct chat is created. + * @returns The created direct chat object. + */ + +export const CREATE_GROUP_CHAT = gql` + mutation createGroupChat( + $userIds: [ID!]! + $organizationId: ID! + $title: String! + ) { + createGroupChat( + data: { + userIds: $userIds + organizationId: $organizationId + title: $title + } + ) { + _id + } + } +`; + +export const CREATE_DIRECT_CHAT = gql` + mutation createDirectChat($userIds: [ID!]!, $organizationId: ID) { + createDirectChat( + data: { userIds: $userIds, organizationId: $organizationId } + ) { + _id + } + } +`; + +export const SEND_MESSAGE_TO_DIRECT_CHAT = gql` + mutation sendMessageToDirectChat($chatId: ID!, $messageContent: String!) { + sendMessageToDirectChat(chatId: $chatId, messageContent: $messageContent) { + _id + createdAt + messageContent + receiver { + _id + firstName + lastName + } + sender { + _id + firstName + lastName + } + updatedAt + } + } +`; + +export const SEND_MESSAGE_TO_GROUP_CHAT = gql` + mutation sendMessageToGroupChat($chatId: ID!, $messageContent: String!) { + sendMessageToGroupChat(chatId: $chatId, messageContent: $messageContent) { + _id + createdAt + messageContent + sender { + _id + firstName + lastName + } + updatedAt + } + } +`; + +export const CREATE_MESSAGE_CHAT = gql` + mutation createMessageChat($receiver: ID!, $messageContent: String!) { + createMessageChat(data: { receiver: $receiver, message: $messageContent }) { + _id + createdAt + message + languageBarrier + receiver { + _id + } + sender { + _id + } + updatedAt + } + } +`; + +export const MESSAGE_SENT_TO_DIRECT_CHAT = gql` + subscription messageSentToDirectChat($userId: ID!) { + messageSentToDirectChat(userId: $userId) { + _id + createdAt + directChatMessageBelongsTo { + _id + } + messageContent + receiver { + _id + firstName + lastName + } + sender { + _id + firstName + lastName + } + updatedAt + } + } +`; + +export const MESSAGE_SENT_TO_GROUP_CHAT = gql` + subscription messageSentToGroupChat($userId: ID!) { + messageSentToGroupChat(userId: $userId) { + _id + createdAt + groupChatMessageBelongsTo { + _id + } + messageContent + sender { + _id + firstName + lastName + } + updatedAt + } + } +`; +//Plugin WebSocket listner + +/** + * GraphQL subscription to listen for updates on plugins. + * + * @returns An object containing information about the updated plugin. + */ + +export const PLUGIN_SUBSCRIPTION = gql` + subscription onPluginUpdate { + onPluginUpdate { + pluginName + _id + pluginDesc + uninstalledOrgs + } + } +`; + +/** + * GraphQL mutation to toggle the pinned status of a post. + * + * @param id - The ID of the post to be toggled. + * @returns The updated post object with the new pinned status. + */ + +export const TOGGLE_PINNED_POST = gql` + mutation TogglePostPin($id: ID!) { + togglePostPin(id: $id) { + _id + } + } +`; + +/** + * GraphQL mutation to add a custom field to an organization. + * + * @param organizationId - The ID of the organization where the custom field is being added. + * @param type - The type of the custom field (e.g., String, Number). + * @param name - The name of the custom field. + * @returns The added organization custom field object. + */ + +export const ADD_CUSTOM_FIELD = gql` + mutation ($organizationId: ID!, $type: String!, $name: String!) { + addOrganizationCustomField( + organizationId: $organizationId + type: $type + name: $name + ) { + name + type + } + } +`; + +// Handles custom organization fields + +/** + * GraphQL mutation to remove a custom field from an organization. + * + * @param organizationId - The ID of the organization from which the custom field is being removed. + * @param customFieldId - The ID of the custom field to be removed. + * @returns The removed organization custom field object. + */ + +export const REMOVE_CUSTOM_FIELD = gql` + mutation ($organizationId: ID!, $customFieldId: ID!) { + removeOrganizationCustomField( + organizationId: $organizationId + customFieldId: $customFieldId + ) { + type + name + } + } +`; + +export const SEND_MEMBERSHIP_REQUEST = gql` + mutation ($organizationId: ID!) { + sendMembershipRequest(organizationId: $organizationId) { + _id + organization { + _id + name + } + user { + _id + } + } + } +`; + +export const JOIN_PUBLIC_ORGANIZATION = gql` + mutation ($organizationId: ID!) { + joinPublicOrganization(organizationId: $organizationId) { + _id + } + } +`; + +export const CANCEL_MEMBERSHIP_REQUEST = gql` + mutation ($membershipRequestId: ID!) { + cancelMembershipRequest(membershipRequestId: $membershipRequestId) { + _id + } + } +`; diff --git a/src/GraphQl/Mutations/PledgeMutation.ts b/src/GraphQl/Mutations/PledgeMutation.ts new file mode 100644 index 0000000000..321f7aa697 --- /dev/null +++ b/src/GraphQl/Mutations/PledgeMutation.ts @@ -0,0 +1,84 @@ +import gql from 'graphql-tag'; + +/** + * GraphQL mutation to create a pledge. + * + * @param campaignId - The ID of the campaign the pledge is associated with. + * @param amount - The amount of the pledge. + * @param currency - The currency of the pledge. + * @param startDate - The start date of the pledge. + * @param endDate - The end date of the pledge. + * @param userIds - The IDs of the users associated with the pledge. + * @returns The ID of the created pledge. + */ +export const CREATE_PlEDGE = gql` + mutation CreateFundraisingCampaignPledge( + $campaignId: ID! + $amount: Float! + $currency: Currency! + $startDate: Date! + $endDate: Date! + $userIds: [ID!]! + ) { + createFundraisingCampaignPledge( + data: { + campaignId: $campaignId + amount: $amount + currency: $currency + startDate: $startDate + endDate: $endDate + userIds: $userIds + } + ) { + _id + } + } +`; + +/** + * GraphQL mutation to update a pledge. + * + * @param id - The ID of the pledge being updated. + * @param amount - The amount of the pledge. + * @param currency - The currency of the pledge. + * @param startDate - The start date of the pledge. + * @param endDate - The end date of the pledge. + * @returns The ID of the updated pledge. + */ +export const UPDATE_PLEDGE = gql` + mutation UpdateFundraisingCampaignPledge( + $id: ID! + $amount: Float + $currency: Currency + $startDate: Date + $endDate: Date + $users: [ID!] + ) { + updateFundraisingCampaignPledge( + id: $id + data: { + users: $users + amount: $amount + currency: $currency + startDate: $startDate + endDate: $endDate + } + ) { + _id + } + } +`; + +/** + * GraphQL mutation to delete a pledge. + * + * @param id - The ID of the pledge being deleted. + * @returns Whether the pledge was successfully deleted. + */ +export const DELETE_PLEDGE = gql` + mutation DeleteFundraisingCampaignPledge($id: ID!) { + removeFundraisingCampaignPledge(id: $id) { + _id + } + } +`; diff --git a/src/GraphQl/Mutations/VenueMutations.ts b/src/GraphQl/Mutations/VenueMutations.ts new file mode 100644 index 0000000000..44ccc1f63e --- /dev/null +++ b/src/GraphQl/Mutations/VenueMutations.ts @@ -0,0 +1,79 @@ +import gql from 'graphql-tag'; + +/** + * GraphQL mutation to create a venue. + * + * @param name - Name of the venue. + * @param capacity - Ineteger representing capacity of venue. + * @param description - Description of the venue. + * @param file - Image file for the venue. + * @param organizationId - Organization to which the ActionItemCategory belongs. + */ + +export const CREATE_VENUE_MUTATION = gql` + mutation createVenue( + $capacity: Int! + $description: String + $file: String + $name: String! + $organizationId: ID! + ) { + createVenue( + data: { + capacity: $capacity + description: $description + file: $file + name: $name + organizationId: $organizationId + } + ) { + _id + } + } +`; + +/** + * GraphQL mutation to update a venue. + * + * @param id - The id of the Venue to be updated. + * @param capacity - Ineteger representing capacity of venue. + * @param description - Description of the venue. + * @param file - Image file for the venue. + * @param name - Name of the venue. + */ + +export const UPDATE_VENUE_MUTATION = gql` + mutation editVenue( + $capacity: Int + $description: String + $file: String + $id: ID! + $name: String + ) { + editVenue( + data: { + capacity: $capacity + description: $description + file: $file + id: $id + name: $name + } + ) { + _id + } + } +`; + +/** + * GraphQL mutation to delete a venue. + * + * @param id - The id of the Venue to be deleted. + */ + +export const DELETE_VENUE_MUTATION = gql` + mutation DeleteVenue($id: ID!) { + deleteVenue(id: $id) { + _id + } + } +`; diff --git a/src/GraphQl/Mutations/mutations.ts b/src/GraphQl/Mutations/mutations.ts new file mode 100644 index 0000000000..69e4c85e9e --- /dev/null +++ b/src/GraphQl/Mutations/mutations.ts @@ -0,0 +1,737 @@ +import gql from 'graphql-tag'; + +export const UNBLOCK_USER_MUTATION = gql` + mutation UnblockUser($userId: ID!, $orgId: ID!) { + unblockUser(organizationId: $orgId, userId: $userId) { + _id + } + } +`; + +// to block the user + +export const BLOCK_USER_MUTATION = gql` + mutation BlockUser($userId: ID!, $orgId: ID!) { + blockUser(organizationId: $orgId, userId: $userId) { + _id + } + } +`; + +// to reject the organization request + +export const REJECT_ORGANIZATION_REQUEST_MUTATION = gql` + mutation RejectMembershipRequest($id: ID!) { + rejectMembershipRequest(membershipRequestId: $id) { + _id + } + } +`; + +// to accept the organization request + +export const ACCEPT_ORGANIZATION_REQUEST_MUTATION = gql` + mutation AcceptMembershipRequest($id: ID!) { + acceptMembershipRequest(membershipRequestId: $id) { + _id + } + } +`; + +// to update the organization details + +export const UPDATE_ORGANIZATION_MUTATION = gql` + mutation UpdateOrganization( + $id: ID! + $name: String + $description: String + $address: AddressInput + $userRegistrationRequired: Boolean + $visibleInSearch: Boolean + $file: String + ) { + updateOrganization( + id: $id + data: { + name: $name + description: $description + userRegistrationRequired: $userRegistrationRequired + visibleInSearch: $visibleInSearch + address: $address + } + file: $file + ) { + _id + } + } +`; + +// fragment for defining the Address input type. +export const ADDRESS_DETAILS_FRAGMENT = gql` + fragment AddressDetails on AddressInput { + city: String + countryCode: String + dependentLocality: String + line1: String + line2: String + postalCode: String + sortingCode: String + state: String + } +`; + +// to update the details of the user + +export const UPDATE_USER_MUTATION = gql` + mutation UpdateUserProfile( + $firstName: String + $lastName: String + $gender: Gender + $email: EmailAddress + $phoneNumber: PhoneNumber + $birthDate: Date + $grade: EducationGrade + $empStatus: EmploymentStatus + $maritalStatus: MaritalStatus + $address: String + $state: String + $country: String + $image: String + $appLanguageCode: String + ) { + updateUserProfile( + data: { + firstName: $firstName + lastName: $lastName + gender: $gender + email: $email + phone: { mobile: $phoneNumber } + birthDate: $birthDate + educationGrade: $grade + employmentStatus: $empStatus + maritalStatus: $maritalStatus + address: { line1: $address, state: $state, countryCode: $country } + appLanguageCode: $appLanguageCode + } + file: $image + ) { + _id + } + } +`; + +// to update the password of user + +export const UPDATE_USER_PASSWORD_MUTATION = gql` + mutation UpdateUserPassword( + $previousPassword: String! + $newPassword: String! + $confirmNewPassword: String! + ) { + updateUserPassword( + data: { + previousPassword: $previousPassword + newPassword: $newPassword + confirmNewPassword: $confirmNewPassword + } + ) { + user { + _id + } + } + } +`; + +// to sign up in the talawa admin + +export const SIGNUP_MUTATION = gql` + mutation SignUp( + $firstName: String! + $lastName: String! + $email: EmailAddress! + $password: String! + $orgId: ID! + ) { + signUp( + data: { + firstName: $firstName + lastName: $lastName + email: $email + password: $password + selectedOrganization: $orgId + } + ) { + user { + _id + } + accessToken + refreshToken + } + } +`; + +// to login in the talawa admin + +export const LOGIN_MUTATION = gql` + mutation Login($email: EmailAddress!, $password: String!) { + login(data: { email: $email, password: $password }) { + user { + _id + firstName + lastName + image + email + } + appUserProfile { + adminFor { + _id + } + isSuperAdmin + appLanguageCode + } + accessToken + refreshToken + } + } +`; + +// to get the refresh token + +export const REFRESH_TOKEN_MUTATION = gql` + mutation RefreshToken($refreshToken: String!) { + refreshToken(refreshToken: $refreshToken) { + refreshToken + accessToken + } + } +`; + +// to revoke a refresh token + +export const REVOKE_REFRESH_TOKEN = gql` + mutation RevokeRefreshTokenForUser { + revokeRefreshTokenForUser + } +`; + +// To verify the google recaptcha + +export const RECAPTCHA_MUTATION = gql` + mutation Recaptcha($recaptchaToken: String!) { + recaptcha(data: { recaptchaToken: $recaptchaToken }) + } +`; + +// to create the organization + +export const CREATE_ORGANIZATION_MUTATION = gql` + mutation CreateOrganization( + $description: String! + $address: AddressInput! + $name: String! + $visibleInSearch: Boolean! + $userRegistrationRequired: Boolean! + $image: String + ) { + createOrganization( + data: { + description: $description + address: $address + name: $name + visibleInSearch: $visibleInSearch + userRegistrationRequired: $userRegistrationRequired + } + file: $image + ) { + _id + } + } +`; + +// to delete the organization + +export const DELETE_ORGANIZATION_MUTATION = gql` + mutation RemoveOrganization($id: ID!) { + removeOrganization(id: $id) { + user { + _id + } + } + } +`; + +// to create the event by any organization + +export const CREATE_EVENT_MUTATION = gql` + mutation CreateEvent( + $title: String! + $description: String! + $recurring: Boolean! + $isPublic: Boolean! + $isRegisterable: Boolean! + $organizationId: ID! + $startDate: Date! + $endDate: Date! + $allDay: Boolean! + $startTime: Time + $endTime: Time + $location: String + $recurrenceStartDate: Date + $recurrenceEndDate: Date + $frequency: Frequency + $weekDays: [WeekDays] + $count: PositiveInt + $interval: PositiveInt + $weekDayOccurenceInMonth: Int + ) { + createEvent( + data: { + title: $title + description: $description + recurring: $recurring + isPublic: $isPublic + isRegisterable: $isRegisterable + organizationId: $organizationId + startDate: $startDate + endDate: $endDate + allDay: $allDay + startTime: $startTime + endTime: $endTime + location: $location + } + recurrenceRuleData: { + recurrenceStartDate: $recurrenceStartDate + recurrenceEndDate: $recurrenceEndDate + frequency: $frequency + weekDays: $weekDays + interval: $interval + count: $count + weekDayOccurenceInMonth: $weekDayOccurenceInMonth + } + ) { + _id + } + } +`; + +// to delete any event by any organization + +export const DELETE_EVENT_MUTATION = gql` + mutation RemoveEvent( + $id: ID! + $recurringEventDeleteType: RecurringEventMutationType + ) { + removeEvent(id: $id, recurringEventDeleteType: $recurringEventDeleteType) { + _id + } + } +`; + +// to remove an admin from an organization +export const REMOVE_ADMIN_MUTATION = gql` + mutation RemoveAdmin($orgid: ID!, $userid: ID!) { + removeAdmin(data: { organizationId: $orgid, userId: $userid }) { + _id + } + } +`; + +// to Remove member from an organization +export const REMOVE_MEMBER_MUTATION = gql` + mutation RemoveMember($orgid: ID!, $userid: ID!) { + removeMember(data: { organizationId: $orgid, userId: $userid }) { + _id + } + } +`; + +// to add the admin +export const ADD_ADMIN_MUTATION = gql` + mutation CreateAdmin($orgid: ID!, $userid: ID!) { + createAdmin(data: { organizationId: $orgid, userId: $userid }) { + user { + _id + } + } + } +`; + +export const ADD_MEMBER_MUTATION = gql` + mutation CreateMember($orgid: ID!, $userid: ID!) { + createMember(input: { organizationId: $orgid, userId: $userid }) { + organization { + _id + } + } + } +`; + +export const CREATE_POST_MUTATION = gql` + mutation CreatePost( + $text: String! + $title: String! + $imageUrl: URL + $videoUrl: URL + $organizationId: ID! + $file: String + $pinned: Boolean + ) { + createPost( + data: { + text: $text + title: $title + imageUrl: $imageUrl + videoUrl: $videoUrl + organizationId: $organizationId + pinned: $pinned + } + file: $file + ) { + _id + } + } +`; + +export const DELETE_POST_MUTATION = gql` + mutation RemovePost($id: ID!) { + removePost(id: $id) { + _id + } + } +`; + +export const GENERATE_OTP_MUTATION = gql` + mutation Otp($email: EmailAddress!) { + otp(data: { email: $email }) { + otpToken + } + } +`; + +export const FORGOT_PASSWORD_MUTATION = gql` + mutation ForgotPassword( + $userOtp: String! + $newPassword: String! + $otpToken: String! + ) { + forgotPassword( + data: { + userOtp: $userOtp + newPassword: $newPassword + otpToken: $otpToken + } + ) + } +`; + +/** + * {@label UPDATE_INSTALL_STATUS_PLUGIN_MUTATION} + * @remarks + * used to toggle `installStatus` (boolean value) of a Plugin + */ +export const UPDATE_INSTALL_STATUS_PLUGIN_MUTATION = gql` + mutation ($id: ID!, $orgId: ID!) { + updatePluginStatus(id: $id, orgId: $orgId) { + _id + pluginName + pluginCreatedBy + pluginDesc + uninstalledOrgs + } + } +`; + +/** + * {@label UPDATE_ORG_STATUS_PLUGIN_MUTATION} + * @remarks + * used `updatePluginStatus`to add or remove the current Organization the in the plugin list `uninstalledOrgs` + */ +export const UPDATE_ORG_STATUS_PLUGIN_MUTATION = gql` + mutation update_install_status_plugin_mutation($id: ID!, $orgId: ID!) { + updatePluginStatus(id: $id, orgId: $orgId) { + _id + pluginName + pluginCreatedBy + pluginDesc + uninstalledOrgs + } + } +`; + +/** + * {@label ADD_PLUGIN_MUTATION} + * @remarks + * used `createPlugin` to add new Plugin in database + */ +export const ADD_PLUGIN_MUTATION = gql` + mutation add_plugin_mutation( + $pluginName: String! + $pluginCreatedBy: String! + $pluginDesc: String! + ) { + createPlugin( + pluginName: $pluginName + pluginCreatedBy: $pluginCreatedBy + pluginDesc: $pluginDesc + ) { + _id + pluginName + pluginCreatedBy + pluginDesc + } + } +`; +export const ADD_ADVERTISEMENT_MUTATION = gql` + mutation ( + $organizationId: ID! + $name: String! + $type: AdvertisementType! + $startDate: Date! + $endDate: Date! + $file: String! + ) { + createAdvertisement( + input: { + organizationId: $organizationId + name: $name + type: $type + startDate: $startDate + endDate: $endDate + mediaFile: $file + } + ) { + advertisement { + _id + } + } + } +`; +export const UPDATE_ADVERTISEMENT_MUTATION = gql` + mutation UpdateAdvertisement( + $id: ID! + $name: String + $file: String + $type: AdvertisementType + $startDate: Date + $endDate: Date + ) { + updateAdvertisement( + input: { + _id: $id + name: $name + mediaFile: $file + type: $type + startDate: $startDate + endDate: $endDate + } + ) { + advertisement { + _id + } + } + } +`; +export const DELETE_ADVERTISEMENT_BY_ID = gql` + mutation ($id: ID!) { + deleteAdvertisement(id: $id) { + advertisement { + _id + } + } + } +`; +export const UPDATE_POST_MUTATION = gql` + mutation UpdatePost( + $id: ID! + $title: String + $text: String + $imageUrl: String + $videoUrl: String + ) { + updatePost( + id: $id + data: { + title: $title + text: $text + imageUrl: $imageUrl + videoUrl: $videoUrl + } + ) { + _id + } + } +`; + +export const UPDATE_EVENT_MUTATION = gql` + mutation UpdateEvent( + $id: ID! + $title: String + $description: String + $recurring: Boolean + $recurringEventUpdateType: RecurringEventMutationType + $isPublic: Boolean + $isRegisterable: Boolean + $allDay: Boolean + $startDate: Date + $endDate: Date + $startTime: Time + $endTime: Time + $location: String + $recurrenceStartDate: Date + $recurrenceEndDate: Date + $frequency: Frequency + $weekDays: [WeekDays] + $count: PositiveInt + $interval: PositiveInt + $weekDayOccurenceInMonth: Int + ) { + updateEvent( + id: $id + data: { + title: $title + description: $description + recurring: $recurring + isPublic: $isPublic + isRegisterable: $isRegisterable + allDay: $allDay + startDate: $startDate + endDate: $endDate + startTime: $startTime + endTime: $endTime + location: $location + } + recurrenceRuleData: { + recurrenceStartDate: $recurrenceStartDate + recurrenceEndDate: $recurrenceEndDate + frequency: $frequency + weekDays: $weekDays + interval: $interval + count: $count + weekDayOccurenceInMonth: $weekDayOccurenceInMonth + } + recurringEventUpdateType: $recurringEventUpdateType + ) { + _id + } + } +`; + +export const LIKE_POST = gql` + mutation likePost($postId: ID!) { + likePost(id: $postId) { + _id + } + } +`; + +export const UNLIKE_POST = gql` + mutation unlikePost($postId: ID!) { + unlikePost(id: $postId) { + _id + } + } +`; + +export const REGISTER_EVENT = gql` + mutation registerForEvent($eventId: ID!) { + registerForEvent(id: $eventId) { + _id + } + } +`; + +export const UPDATE_COMMUNITY = gql` + mutation updateCommunity($data: UpdateCommunityInput!) { + updateCommunity(data: $data) + } +`; + +export const RESET_COMMUNITY = gql` + mutation resetCommunity { + resetCommunity + } +`; + +export const DONATE_TO_ORGANIZATION = gql` + mutation donate( + $userId: ID! + $createDonationOrgId2: ID! + $payPalId: ID! + $nameOfUser: String! + $amount: Float! + $nameOfOrg: String! + ) { + createDonation( + userId: $userId + orgId: $createDonationOrgId2 + payPalId: $payPalId + nameOfUser: $nameOfUser + amount: $amount + nameOfOrg: $nameOfOrg + ) { + _id + amount + nameOfUser + nameOfOrg + } + } +`; + +// Create and Update Action Item Categories +export { + CREATE_ACTION_ITEM_CATEGORY_MUTATION, + UPDATE_ACTION_ITEM_CATEGORY_MUTATION, +} from './ActionItemCategoryMutations'; + +// Create, Update and Delete Action Items +export { + CREATE_ACTION_ITEM_MUTATION, + DELETE_ACTION_ITEM_MUTATION, + UPDATE_ACTION_ITEM_MUTATION, +} from './ActionItemMutations'; + +export { + CREATE_AGENDA_ITEM_CATEGORY_MUTATION, + DELETE_AGENDA_ITEM_CATEGORY_MUTATION, + UPDATE_AGENDA_ITEM_CATEGORY_MUTATION, +} from './AgendaCategoryMutations'; + +export { + CREATE_AGENDA_ITEM_MUTATION, + DELETE_AGENDA_ITEM_MUTATION, + UPDATE_AGENDA_ITEM_MUTATION, +} from './AgendaItemMutations'; + +// Changes the role of a event in an organization and add and remove the event from the organization +export { + ADD_EVENT_ATTENDEE, + MARK_CHECKIN, + REMOVE_EVENT_ATTENDEE, +} from './EventAttendeeMutations'; + +// Create the new comment on a post and Like and Unlike the comment +export { + CREATE_COMMENT_POST, + LIKE_COMMENT, + UNLIKE_COMMENT, +} from './CommentMutations'; + +// Changes the role of a user in an organization +export { + ADD_CUSTOM_FIELD, + CREATE_DIRECT_CHAT, + CREATE_SAMPLE_ORGANIZATION_MUTATION, + JOIN_PUBLIC_ORGANIZATION, + PLUGIN_SUBSCRIPTION, + REMOVE_CUSTOM_FIELD, + REMOVE_SAMPLE_ORGANIZATION_MUTATION, + SEND_MEMBERSHIP_REQUEST, + TOGGLE_PINNED_POST, + UPDATE_USER_ROLE_IN_ORG_MUTATION, +} from './OrganizationMutations'; + +export { + CREATE_VENUE_MUTATION, + DELETE_VENUE_MUTATION, + UPDATE_VENUE_MUTATION, +} from './VenueMutations'; diff --git a/src/GraphQl/Queries/ActionItemCategoryQueries.ts b/src/GraphQl/Queries/ActionItemCategoryQueries.ts new file mode 100644 index 0000000000..50c526f129 --- /dev/null +++ b/src/GraphQl/Queries/ActionItemCategoryQueries.ts @@ -0,0 +1,18 @@ +import gql from 'graphql-tag'; + +/** + * GraphQL query to retrieve action item categories by organization. + * + * @param organizationId - The ID of the organization for which action item categories are being retrieved. + * @returns The list of action item categories associated with the organization. + */ + +export const ACTION_ITEM_CATEGORY_LIST = gql` + query ActionItemCategoriesByOrganization($organizationId: ID!) { + actionItemCategoriesByOrganization(organizationId: $organizationId) { + _id + name + isDisabled + } + } +`; diff --git a/src/GraphQl/Queries/ActionItemQueries.ts b/src/GraphQl/Queries/ActionItemQueries.ts new file mode 100644 index 0000000000..0ce9f1acab --- /dev/null +++ b/src/GraphQl/Queries/ActionItemQueries.ts @@ -0,0 +1,103 @@ +import gql from 'graphql-tag'; + +/** + * GraphQL query to retrieve action item categories by organization. + * + * @param organizationId - The ID of the organization for which action item categories are being retrieved. + * @param orderBy - Sort action items Latest/Earliest first. + * @param actionItemCategory_id - Filter action items belonging to an action item category. + * @param event_id - Filter action items belonging to an event. + * @param is_active - Filter all the active action items. + * @param is_completed - Filter all the completed action items. + * @returns The list of action item categories associated with the organization. + */ + +export const ACTION_ITEM_LIST = gql` + query ActionItemsByOrganization( + $organizationId: ID! + $actionItemCategoryId: ID + $eventId: ID + $isActive: Boolean + $isCompleted: Boolean + $orderBy: ActionItemsOrderByInput + ) { + actionItemsByOrganization( + organizationId: $organizationId + orderBy: $orderBy + where: { + actionItemCategory_id: $actionItemCategoryId + event_id: $eventId + is_active: $isActive + is_completed: $isCompleted + } + ) { + _id + assignee { + _id + firstName + lastName + } + assigner { + _id + firstName + lastName + } + actionItemCategory { + _id + name + } + preCompletionNotes + postCompletionNotes + assignmentDate + dueDate + completionDate + isCompleted + event { + _id + title + } + creator { + _id + firstName + lastName + } + } + } +`; + +export const ACTION_ITEM_LIST_BY_EVENTS = gql` + query actionItemsByEvent($eventId: ID!) { + actionItemsByEvent(eventId: $eventId) { + _id + assignee { + _id + firstName + lastName + } + assigner { + _id + firstName + lastName + } + actionItemCategory { + _id + name + } + preCompletionNotes + postCompletionNotes + assignmentDate + dueDate + completionDate + isCompleted + event { + _id + title + } + creator { + _id + firstName + lastName + } + } + } +`; diff --git a/src/GraphQl/Queries/AgendaCategoryQueries.ts b/src/GraphQl/Queries/AgendaCategoryQueries.ts new file mode 100644 index 0000000000..f766337c22 --- /dev/null +++ b/src/GraphQl/Queries/AgendaCategoryQueries.ts @@ -0,0 +1,23 @@ +import gql from 'graphql-tag'; + +/** + * GraphQL query to retrieve agenda category by id. + * + * @param agendaCategoryId - The ID of the category which is being retrieved. + * @returns Agenda category associated with the id. + */ + +export const AGENDA_ITEM_CATEGORY_LIST = gql` + query AgendaItemCategoriesByOrganization($organizationId: ID!) { + agendaItemCategoriesByOrganization(organizationId: $organizationId) { + _id + name + description + createdBy { + _id + firstName + lastName + } + } + } +`; diff --git a/src/GraphQl/Queries/AgendaItemQueries.ts b/src/GraphQl/Queries/AgendaItemQueries.ts new file mode 100644 index 0000000000..92957983c8 --- /dev/null +++ b/src/GraphQl/Queries/AgendaItemQueries.ts @@ -0,0 +1,73 @@ +import gql from 'graphql-tag'; + +export const AgendaItemByOrganization = gql` + query AgendaItemByOrganization($organizationId: ID!) { + agendaItemByOrganization(organizationId: $organizationId) { + _id + title + description + duration + attachments + createdBy { + _id + firstName + lastName + } + urls + users { + _id + firstName + lastName + } + categories { + _id + name + } + sequence + organization { + _id + name + } + relatedEvent { + _id + title + } + } + } +`; + +export const AgendaItemByEvent = gql` + query AgendaItemByEvent($relatedEventId: ID!) { + agendaItemByEvent(relatedEventId: $relatedEventId) { + _id + title + description + duration + attachments + createdBy { + _id + firstName + lastName + } + urls + users { + _id + firstName + lastName + } + sequence + categories { + _id + name + } + organization { + _id + name + } + relatedEvent { + _id + title + } + } + } +`; diff --git a/src/GraphQl/Queries/OrganizationQueries.ts b/src/GraphQl/Queries/OrganizationQueries.ts new file mode 100644 index 0000000000..2d199359bf --- /dev/null +++ b/src/GraphQl/Queries/OrganizationQueries.ts @@ -0,0 +1,320 @@ +// OrganizationQueries.js +import gql from 'graphql-tag'; + +// display posts + +/** + * GraphQL query to retrieve the list of organizations. + * + * @param first - Optional. Number of organizations to retrieve in the first batch. + * @param skip - Optional. Number of organizations to skip before starting to collect the result set. + * @param filter - Optional. Filter organizations by a specified string. + * @param id - Optional. The ID of a specific organization to retrieve. + * @returns The list of organizations based on the applied filters. + */ +export const ORGANIZATION_POST_LIST = gql` + query Organizations( + $id: ID! + $after: String + $before: String + $first: PositiveInt + $last: PositiveInt + ) { + organizations(id: $id) { + posts(after: $after, before: $before, first: $first, last: $last) { + edges { + node { + _id + title + text + imageUrl + videoUrl + creator { + _id + firstName + lastName + email + } + createdAt + likeCount + likedBy { + _id + firstName + lastName + } + commentCount + comments { + _id + text + creator { + _id + } + createdAt + likeCount + likedBy { + _id + } + } + pinned + } + cursor + } + pageInfo { + startCursor + endCursor + hasNextPage + hasPreviousPage + } + totalCount + } + } + } +`; + +export const ORGANIZATION_ADVERTISEMENT_LIST = gql` + query Organizations( + $id: ID! + $after: String + $before: String + $first: Int + $last: Int + ) { + organizations(id: $id) { + _id + advertisements( + after: $after + before: $before + first: $first + last: $last + ) { + edges { + node { + _id + name + startDate + endDate + mediaUrl + } + cursor + } + pageInfo { + startCursor + endCursor + hasNextPage + hasPreviousPage + } + totalCount + } + } + } +`; + +/** + * GraphQL query to retrieve organizations based on user connection. + * + * @param first - Optional. Number of organizations to retrieve in the first batch. + * @param skip - Optional. Number of organizations to skip before starting to collect the result set. + * @param filter - Optional. Filter organizations by a specified string. + * @param id - Optional. The ID of a specific organization to retrieve. + * @returns The list of organizations based on the applied filters. + */ + +export const USER_ORGANIZATION_CONNECTION = gql` + query organizationsConnection( + $first: Int + $skip: Int + $filter: String + $id: ID + ) { + organizationsConnection( + first: $first + skip: $skip + where: { name_contains: $filter, id: $id } + orderBy: name_ASC + ) { + _id + name + image + description + userRegistrationRequired + creator { + firstName + lastName + } + members { + _id + } + admins { + _id + } + createdAt + address { + city + countryCode + dependentLocality + line1 + line2 + postalCode + sortingCode + state + } + membershipRequests { + _id + user { + _id + } + } + } + } +`; + +/** + * GraphQL query to retrieve organizations joined by a user. + * + * @param id - The ID of the user for which joined organizations are being retrieved. + * @returns The list of organizations joined by the user. + */ + +export const USER_JOINED_ORGANIZATIONS = gql` + query UserJoinedOrganizations($id: ID!) { + users(where: { id: $id }) { + user { + joinedOrganizations { + _id + name + description + image + members { + _id + } + address { + city + countryCode + dependentLocality + line1 + line2 + postalCode + sortingCode + state + } + admins { + _id + } + } + } + } + } +`; + +/** + * GraphQL query to retrieve organizations created by a user. + * + * @param id - The ID of the user for which created organizations are being retrieved. + * @returns The list of organizations created by the user. + */ + +export const USER_CREATED_ORGANIZATIONS = gql` + query UserCreatedOrganizations($id: ID!) { + users(where: { id: $id }) { + appUserProfile { + createdOrganizations { + _id + name + description + image + members { + _id + } + address { + city + countryCode + dependentLocality + line1 + line2 + postalCode + sortingCode + state + } + admins { + _id + } + } + } + } + } +`; + +/** + * GraphQL query to retrieve the list of admins for a specific organization. + * + * @param id - The ID of the organization for which admins are being retrieved. + * @returns The list of admins associated with the organization. + */ + +export const ORGANIZATION_ADMINS_LIST = gql` + query Organizations($id: ID!) { + organizations(id: $id) { + _id + admins { + _id + image + firstName + lastName + email + } + } + } +`; + +/** + * GraphQL query to retrieve the list of members for a specific organization. + * + * @param id - The ID of the organization for which members are being retrieved. + * @returns The list of members associated with the organization. + */ +export const ORGANIZATION_FUNDS = gql` + query Organizations($id: ID!) { + organizations(id: $id) { + funds { + _id + name + refrenceNumber + taxDeductible + isArchived + isDefault + createdAt + } + } + } +`; + +/** + * GraphQL query to retrieve the list of venues for a specific organization. + * + * @param id - The ID of the organization for which venues are being retrieved. + * @returns The list of venues associated with the organization. + */ +export const VENUE_LIST = gql` + query GetVenueByOrgId( + $orgId: ID! + $first: Int + $orderBy: VenueOrderByInput + $where: VenueWhereInput + ) { + getVenueByOrgId( + orgId: $orgId + first: $first + orderBy: $orderBy + where: $where + ) { + _id + capacity + name + description + imageUrl + organization { + _id + } + } + } +`; diff --git a/src/GraphQl/Queries/PlugInQueries.ts b/src/GraphQl/Queries/PlugInQueries.ts new file mode 100644 index 0000000000..c93b3ad267 --- /dev/null +++ b/src/GraphQl/Queries/PlugInQueries.ts @@ -0,0 +1,328 @@ +import gql from 'graphql-tag'; + +/** + * GraphQL query to retrieve a list of plugins. + * + * @returns The list of plugins with details such as ID, name, creator, description, and uninstalled organizations. + */ + +export const PLUGIN_GET = gql` + query getPluginList { + getPlugins { + _id + pluginName + pluginCreatedBy + pluginDesc + uninstalledOrgs + } + } +`; + +/** + * GraphQL query to retrieve a list of advertisements. + * + * @returns The list of advertisements with details such as ID, name, type, organization ID, link, start date, and end date. + */ + +export const ADVERTISEMENTS_GET = gql` + query getAdvertisements { + advertisementsConnection { + edges { + node { + _id + name + type + organization { + _id + } + mediaUrl + endDate + startDate + } + } + } + } +`; + +/** + * GraphQL query to retrieve a list of events based on organization connection. + * + * @param organization_id - The ID of the organization for which events are being retrieved. + * @param title_contains - Optional. Filter events by title containing a specified string. + * @param description_contains - Optional. Filter events by description containing a specified string. + * @param location_contains - Optional. Filter events by location containing a specified string. + * @param first - Optional. Number of events to retrieve in the first batch. + * @param skip - Optional. Number of events to skip before starting to collect the result set. + * @returns The list of events associated with the organization based on the applied filters. + */ + +export const ORGANIZATION_EVENTS_CONNECTION = gql` + query EventsByOrganizationConnection( + $organization_id: ID! + $title_contains: String + $description_contains: String + $location_contains: String + $first: Int + $skip: Int + ) { + eventsByOrganizationConnection( + where: { + organization_id: $organization_id + title_contains: $title_contains + description_contains: $description_contains + location_contains: $location_contains + } + first: $first + skip: $skip + ) { + _id + title + description + startDate + endDate + location + startTime + endTime + allDay + recurring + isPublic + isRegisterable + creator { + _id + firstName + lastName + } + attendees { + _id + } + } + } +`; + +/** + * GraphQL query to retrieve a list of direct chats based on user ID. + * + * @param id - The ID of the user for which direct chats are being retrieved. + * @returns The list of direct chats associated with the user, including details such as ID, creator, messages, organization, and participating users. + */ + +// directChatsMessagesByChatID(id: ID!): [DirectChatMessage] + +export const DIRECT_CHAT_MESSAGES_BY_CHAT_ID = gql` + query directChatsMessagesByChatID($id: ID!) { + directChatsMessagesByChatID(id: $id) { + _id + createdAt + messageContent + receiver { + _id + firstName + lastName + email + image + } + sender { + _id + firstName + lastName + email + image + } + } + } +`; + +export const DIRECT_CHAT_BY_ID = gql` + query directChatById($id: ID!) { + directChatById(id: $id) { + _id + createdAt + messages { + _id + createdAt + messageContent + receiver { + _id + firstName + lastName + email + image + } + sender { + _id + firstName + lastName + email + image + } + } + users { + _id + firstName + lastName + email + } + } + } +`; + +export const GROUP_CHAT_BY_ID = gql` + query groupChatById($id: ID!) { + groupChatById(id: $id) { + _id + createdAt + title + messages { + _id + createdAt + messageContent + sender { + _id + firstName + lastName + email + image + } + } + users { + _id + firstName + lastName + email + image + } + } + } +`; + +// directChatByChatId + +// export const GROUP_CHAT_MESSAGES_BY_CHAT_ID = gql` +// query directChatsMessagesByChatID($id: ID!) { +// directChatsMessagesByChatID(id: $id) { +// _id +// createdAt +// messageContent +// receiver { +// _id +// firstName +// lastName +// email +// } +// sender { +// _id +// firstName +// lastName +// email +// } +// } +// } +// `; + +export const DIRECT_CHATS_LIST = gql` + query DirectChatsByUserID($id: ID!) { + directChatsByUserID(id: $id) { + _id + creator { + _id + firstName + lastName + email + } + messages { + _id + createdAt + messageContent + receiver { + _id + firstName + lastName + email + } + sender { + _id + firstName + lastName + email + } + } + organization { + _id + name + } + users { + _id + firstName + lastName + email + image + } + } + } +`; + +export const GROUP_CHAT_LIST = gql` + query GroupChatsByUserID($id: ID!) { + groupChatsByUserId(id: $id) { + _id + creator { + _id + firstName + lastName + email + } + title + messages { + _id + createdAt + messageContent + sender { + _id + firstName + lastName + email + } + } + organization { + _id + name + } + users { + _id + firstName + lastName + email + image + } + } + } +`; +/** + * GraphQL query to check if an organization is a sample organization. + * + * @param isSampleOrganizationId - The ID of the organization being checked. + * @returns A boolean indicating whether the organization is a sample organization. + */ + +export const IS_SAMPLE_ORGANIZATION_QUERY = gql` + query ($isSampleOrganizationId: ID!) { + isSampleOrganization(id: $isSampleOrganizationId) + } +`; + +/** + * GraphQL query to retrieve custom fields for a specific organization. + * + * @param customFieldsByOrganizationId - The ID of the organization for which custom fields are being retrieved. + * @returns The list of custom fields associated with the organization, including details such as ID, type, and name. + */ + +export const ORGANIZATION_CUSTOM_FIELDS = gql` + query ($customFieldsByOrganizationId: ID!) { + customFieldsByOrganization(id: $customFieldsByOrganizationId) { + _id + type + name + } + } +`; diff --git a/src/GraphQl/Queries/Queries.ts b/src/GraphQl/Queries/Queries.ts new file mode 100644 index 0000000000..1235d65f9f --- /dev/null +++ b/src/GraphQl/Queries/Queries.ts @@ -0,0 +1,813 @@ +import gql from 'graphql-tag'; + +//Query List +// Check Auth +export const CHECK_AUTH = gql` + query { + checkAuth { + _id + firstName + lastName + createdAt + image + email + birthDate + educationGrade + employmentStatus + gender + maritalStatus + phone { + mobile + } + address { + line1 + state + countryCode + } + } + } +`; + +// Query to take the Organization list +export const ORGANIZATION_LIST = gql` + query { + organizations { + _id + image + creator { + firstName + lastName + } + name + members { + _id + } + admins { + _id + } + createdAt + address { + city + countryCode + dependentLocality + line1 + line2 + postalCode + sortingCode + state + } + } + } +`; + +// Query to take the Organization list with filter and sort option +export const ORGANIZATION_CONNECTION_LIST = gql` + query OrganizationsConnection( + $filter: String + $first: Int + $skip: Int + $orderBy: OrganizationOrderByInput + ) { + organizationsConnection( + where: { name_contains: $filter } + first: $first + skip: $skip + orderBy: $orderBy + ) { + _id + image + creator { + firstName + lastName + } + name + members { + _id + } + admins { + _id + } + createdAt + address { + city + countryCode + dependentLocality + line1 + line2 + postalCode + sortingCode + state + } + } + } +`; + +// Query to take the User list +export const USER_LIST = gql` + query Users( + $firstName_contains: String + $lastName_contains: String + $skip: Int + $first: Int + $order: UserOrderByInput + ) { + users( + where: { + firstName_contains: $firstName_contains + lastName_contains: $lastName_contains + } + skip: $skip + first: $first + orderBy: $order + ) { + user { + _id + joinedOrganizations { + _id + name + image + createdAt + address { + city + countryCode + dependentLocality + line1 + line2 + postalCode + sortingCode + state + } + creator { + _id + firstName + lastName + image + email + } + } + firstName + lastName + email + image + createdAt + registeredEvents { + _id + } + organizationsBlockedBy { + _id + name + image + address { + city + countryCode + dependentLocality + line1 + line2 + postalCode + sortingCode + state + } + creator { + _id + firstName + lastName + image + email + } + createdAt + } + membershipRequests { + _id + } + } + appUserProfile { + _id + adminFor { + _id + } + isSuperAdmin + createdOrganizations { + _id + } + createdEvents { + _id + } + eventAdmin { + _id + } + } + } + } +`; +export const USER_LIST_FOR_TABLE = gql` + query Users($firstName_contains: String, $lastName_contains: String) { + users( + where: { + firstName_contains: $firstName_contains + lastName_contains: $lastName_contains + } + ) { + user { + _id + firstName + lastName + email + image + createdAt + } + } + } +`; + +export const USER_LIST_REQUEST = gql` + query Users( + $firstName_contains: String + $lastName_contains: String + $first: Int + $skip: Int + ) { + users( + where: { + firstName_contains: $firstName_contains + lastName_contains: $lastName_contains + } + skip: $skip + first: $first + ) { + user { + firstName + lastName + image + _id + email + createdAt + } + appUserProfile { + _id + adminFor { + _id + } + isSuperAdmin + createdOrganizations { + _id + } + createdEvents { + _id + } + eventAdmin { + _id + } + } + } + } +`; + +export const EVENT_DETAILS = gql` + query Event($id: ID!) { + event(id: $id) { + _id + title + description + startDate + endDate + startTime + endTime + allDay + location + organization { + _id + members { + _id + firstName + lastName + } + } + attendees { + _id + } + } + } +`; + +export const EVENT_ATTENDEES = gql` + query Event($id: ID!) { + event(id: $id) { + attendees { + _id + firstName + lastName + } + } + } +`; + +export const EVENT_CHECKINS = gql` + query eventCheckIns($id: ID!) { + event(id: $id) { + _id + attendeesCheckInStatus { + _id + user { + _id + firstName + lastName + } + checkIn { + _id + time + } + } + } + } +`; + +export const EVENT_FEEDBACKS = gql` + query eventFeedback($id: ID!) { + event(id: $id) { + _id + feedback { + _id + rating + review + } + averageFeedbackScore + } + } +`; + +// Query to take the Organization with data +export const ORGANIZATIONS_LIST = gql` + query Organizations($id: ID!) { + organizations(id: $id) { + _id + image + creator { + firstName + lastName + email + } + name + description + address { + city + countryCode + dependentLocality + line1 + line2 + postalCode + sortingCode + state + } + userRegistrationRequired + visibleInSearch + members { + _id + firstName + lastName + email + } + admins { + _id + firstName + lastName + email + createdAt + } + membershipRequests { + _id + user { + firstName + lastName + email + } + } + blockedUsers { + _id + firstName + lastName + email + } + } + } +`; + +// Query to take the Members of a particular organization +export const MEMBERS_LIST = gql` + query Organizations($id: ID!) { + organizations(id: $id) { + _id + members { + _id + firstName + lastName + image + email + createdAt + organizationsBlockedBy { + _id + } + } + } + } +`; + +export const BLOCK_PAGE_MEMBER_LIST = gql` + query Organizations( + $orgId: ID! + $firstName_contains: String + $lastName_contains: String + ) { + organizationsMemberConnection( + orgId: $orgId + where: { + firstName_contains: $firstName_contains + lastName_contains: $lastName_contains + } + ) { + edges { + _id + firstName + lastName + email + organizationsBlockedBy { + _id + } + } + } + } +`; + +// Query to filter out all the members with the macthing query and a particular OrgId +export const ORGANIZATIONS_MEMBER_CONNECTION_LIST = gql` + query Organizations( + $orgId: ID! + $firstName_contains: String + $lastName_contains: String + $first: Int + $skip: Int + ) { + organizationsMemberConnection( + orgId: $orgId + first: $first + skip: $skip + where: { + firstName_contains: $firstName_contains + lastName_contains: $lastName_contains + } + ) { + edges { + _id + firstName + lastName + image + email + createdAt + } + } + } +`; + +// To take the list of the oranization joined by a user +export const USER_ORGANIZATION_LIST = gql` + query User($userId: ID!) { + user(id: $userId) { + user { + firstName + email + image + lastName + } + } + } +`; + +// To take the details of a user +export const USER_DETAILS = gql` + query User($id: ID!) { + user(id: $id) { + user { + _id + joinedOrganizations { + _id + } + firstName + lastName + email + image + createdAt + birthDate + educationGrade + employmentStatus + gender + maritalStatus + phone { + mobile + } + address { + line1 + countryCode + city + state + } + registeredEvents { + _id + } + membershipRequests { + _id + } + } + appUserProfile { + _id + adminFor { + _id + } + isSuperAdmin + appLanguageCode + pluginCreationAllowed + createdOrganizations { + _id + } + createdEvents { + _id + } + eventAdmin { + _id + } + } + } + } +`; + +// to take the organization event list +export const ORGANIZATION_EVENT_LIST = gql` + query EventsByOrganization($id: ID!) { + eventsByOrganization(id: $id) { + _id + title + description + startDate + endDate + location + startTime + endTime + allDay + recurring + isPublic + isRegisterable + } + } +`; + +export const ORGANIZATION_EVENT_CONNECTION_LIST = gql` + query EventsByOrganizationConnection( + $organization_id: ID! + $title_contains: String + $description_contains: String + $location_contains: String + $first: Int + $skip: Int + ) { + eventsByOrganizationConnection( + where: { + organization_id: $organization_id + title_contains: $title_contains + description_contains: $description_contains + location_contains: $location_contains + } + first: $first + skip: $skip + ) { + _id + title + description + startDate + endDate + location + startTime + endTime + allDay + recurring + recurrenceRule { + recurrenceStartDate + recurrenceEndDate + frequency + weekDays + interval + count + weekDayOccurenceInMonth + } + isRecurringEventException + isPublic + isRegisterable + } + } +`; + +export const ORGANIZATION_DONATION_CONNECTION_LIST = gql` + query GetDonationByOrgIdConnection( + $orgId: ID! + $id: ID + $name_of_user_contains: String + ) { + getDonationByOrgIdConnection( + orgId: $orgId + where: { id: $id, name_of_user_contains: $name_of_user_contains } + ) { + _id + nameOfUser + amount + userId + payPalId + updatedAt + } + } +`; + +// to take the list of the admins of a particular +export const ADMIN_LIST = gql` + query Organizations($id: ID!) { + organizations(id: $id) { + _id + admins { + _id + firstName + lastName + image + email + createdAt + } + } + } +`; + +// to take the membership request +export const MEMBERSHIP_REQUEST = gql` + query Organizations( + $id: ID! + $skip: Int + $first: Int + $firstName_contains: String + ) { + organizations(id: $id) { + _id + membershipRequests( + skip: $skip + first: $first + where: { user: { firstName_contains: $firstName_contains } } + ) { + _id + user { + _id + firstName + lastName + email + } + } + } + } +`; + +export const USERS_CONNECTION_LIST = gql` + query usersConnection( + $id_not_in: [ID!] + $firstName_contains: String + $lastName_contains: String + ) { + users( + where: { + id_not_in: $id_not_in + firstName_contains: $firstName_contains + lastName_contains: $lastName_contains + } + ) { + user { + firstName + lastName + image + _id + email + createdAt + organizationsBlockedBy { + _id + name + image + address { + city + countryCode + dependentLocality + line1 + line2 + postalCode + sortingCode + state + } + createdAt + creator { + _id + firstName + lastName + image + email + createdAt + } + } + joinedOrganizations { + _id + name + image + address { + city + countryCode + dependentLocality + line1 + line2 + postalCode + sortingCode + state + } + createdAt + creator { + _id + firstName + lastName + image + email + createdAt + } + } + } + appUserProfile { + _id + adminFor { + _id + } + isSuperAdmin + createdOrganizations { + _id + } + createdEvents { + _id + } + eventAdmin { + _id + } + } + } + } +`; + +export const GET_COMMUNITY_DATA = gql` + query getCommunityData { + getCommunityData { + _id + websiteLink + name + logoUrl + socialMediaUrls { + facebook + gitHub + instagram + twitter + linkedIn + youTube + reddit + slack + } + } + } +`; + +// get the list of Action Item Categories +export { ACTION_ITEM_CATEGORY_LIST } from './ActionItemCategoryQueries'; + +// get the list of Action Items +export { ACTION_ITEM_LIST } from './ActionItemQueries'; + +export { + AgendaItemByEvent, + AgendaItemByOrganization, +} from './AgendaItemQueries'; + +export { AGENDA_ITEM_CATEGORY_LIST } from './AgendaCategoryQueries'; +// to take the list of the blocked users +export { + ADVERTISEMENTS_GET, + DIRECT_CHATS_LIST, + IS_SAMPLE_ORGANIZATION_QUERY, + ORGANIZATION_CUSTOM_FIELDS, + ORGANIZATION_EVENTS_CONNECTION, + PLUGIN_GET, +} from './PlugInQueries'; + +// display posts +export { + ORGANIZATION_POST_LIST, + ORGANIZATION_ADVERTISEMENT_LIST, +} from './OrganizationQueries'; + +export { + ORGANIZATION_ADMINS_LIST, + USER_CREATED_ORGANIZATIONS, + USER_JOINED_ORGANIZATIONS, + USER_ORGANIZATION_CONNECTION, +} from './OrganizationQueries'; diff --git a/src/GraphQl/Queries/fundQueries.ts b/src/GraphQl/Queries/fundQueries.ts new file mode 100644 index 0000000000..daec99a8c9 --- /dev/null +++ b/src/GraphQl/Queries/fundQueries.ts @@ -0,0 +1,81 @@ +/*eslint-disable*/ +import gql from 'graphql-tag'; + +/** + * GraphQL query to retrieve the list of members for a specific organization. + * + * @param id - The ID of the organization for which members are being retrieved. + * @param filter - The filter to search for a specific member. + * @returns The list of members associated with the organization. + */ +export const FUND_LIST = gql` + query FundsByOrganization( + $organizationId: ID! + $filter: String + $orderBy: FundOrderByInput + ) { + fundsByOrganization( + organizationId: $organizationId + where: { name_contains: $filter } + orderBy: $orderBy + ) { + _id + name + refrenceNumber + taxDeductible + isDefault + isArchived + createdAt + organizationId + creator { + _id + firstName + lastName + } + } + } +`; + +export const FUND_CAMPAIGN = gql` + query GetFundById( + $id: ID! + $where: CampaignWhereInput + $orderBy: CampaignOrderByInput + ) { + getFundById(id: $id, where: $where, orderBy: $orderBy) { + campaigns { + _id + endDate + fundingGoal + name + startDate + currency + } + } + } +`; + +export const FUND_CAMPAIGN_PLEDGE = gql` + query GetFundraisingCampaignById($id: ID!, $orderBy: PledgeOrderByInput) { + getFundraisingCampaignById(id: $id, orderBy: $orderBy) { + name + fundingGoal + currency + startDate + endDate + pledges { + _id + amount + currency + endDate + startDate + users { + _id + firstName + lastName + image + } + } + } + } +`; diff --git a/src/assets/css/app.css b/src/assets/css/app.css new file mode 100644 index 0000000000..d6c5ca665c --- /dev/null +++ b/src/assets/css/app.css @@ -0,0 +1,12527 @@ +@charset "UTF-8"; +@import url('https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap'); +/*! + * Bootstrap v5.3.0 (https://getbootstrap.com/) + * Copyright 2011-2023 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +:root, +[data-bs-theme='light'] { + --bs-blue: #0d6efd; + --bs-indigo: #6610f2; + --bs-purple: #6f42c1; + --bs-pink: #d63384; + --bs-red: #dc3545; + --bs-orange: #fd7e14; + --bs-yellow: #ffc107; + --bs-green: #198754; + --bs-teal: #20c997; + --bs-cyan: #0dcaf0; + --bs-black: #000; + --bs-white: #fff; + --bs-gray: #6c757d; + --bs-gray-dark: #343a40; + --bs-gray-100: #f8f9fa; + --bs-gray-200: #e9ecef; + --bs-gray-300: #dee2e6; + --bs-gray-400: #ced4da; + --bs-gray-500: #adb5bd; + --bs-gray-600: #6c757d; + --bs-gray-700: #495057; + --bs-gray-800: #343a40; + --bs-gray-900: #212529; + --bs-primary: #31bb6b; + --bs-secondary: #707070; + --bs-success: #31bb6b; + --bs-info: #0dcaf0; + --bs-warning: #febc59; + --bs-danger: #dc3545; + --bs-light: #f8f9fa; + --bs-dark: #212529; + --bs-primary-rgb: 49, 187, 107; + --bs-secondary-rgb: 112, 112, 112; + --bs-success-rgb: 49, 187, 107; + --bs-info-rgb: 13, 202, 240; + --bs-warning-rgb: 254, 188, 89; + --bs-danger-rgb: 220, 53, 69; + --bs-light-rgb: 248, 249, 250; + --bs-dark-rgb: 33, 37, 41; + --bs-primary-text-emphasis: #144b2b; + --bs-secondary-text-emphasis: #2d2d2d; + --bs-success-text-emphasis: #144b2b; + --bs-info-text-emphasis: #055160; + --bs-warning-text-emphasis: #664b24; + --bs-danger-text-emphasis: #58151c; + --bs-light-text-emphasis: #495057; + --bs-dark-text-emphasis: #495057; + --bs-primary-bg-subtle: #d6f1e1; + --bs-secondary-bg-subtle: #e2e2e2; + --bs-success-bg-subtle: #d6f1e1; + --bs-info-bg-subtle: #cff4fc; + --bs-warning-bg-subtle: #fff2de; + --bs-danger-bg-subtle: #f8d7da; + --bs-light-bg-subtle: #fcfcfd; + --bs-dark-bg-subtle: #ced4da; + --bs-primary-border-subtle: #ade4c4; + --bs-secondary-border-subtle: #c6c6c6; + --bs-success-border-subtle: #ade4c4; + --bs-info-border-subtle: #9eeaf9; + --bs-warning-border-subtle: #ffe4bd; + --bs-danger-border-subtle: #f1aeb5; + --bs-light-border-subtle: #e9ecef; + --bs-dark-border-subtle: #adb5bd; + --bs-white-rgb: 255, 255, 255; + --bs-black-rgb: 0, 0, 0; + --bs-font-sans-serif: system-ui, -apple-system, 'Segoe UI', Roboto, + 'Helvetica Neue', 'Noto Sans', 'Liberation Sans', Arial, sans-serif, + 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; + --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, + 'Liberation Mono', 'Courier New', monospace; + --bs-font-lato: 'Lato'; + --bs-gradient: linear-gradient( + 180deg, + rgba(255, 255, 255, 0.15), + rgba(255, 255, 255, 0) + ); + --bs-body-font-family: var(--bs-font-sans-serif); + --bs-leftDrawer-font-family: var(--bs-font-sans-serif); + --bs-body-font-size: 1rem; + --bs-body-font-weight: 400; + --bs-body-line-height: 1.5; + --bs-body-color: #212529; + --bs-body-color-rgb: 33, 37, 41; + --bs-body-bg: #fff; + --bs-body-bg-rgb: 255, 255, 255; + --bs-emphasis-color: #000; + --bs-emphasis-color-rgb: 0, 0, 0; + --bs-secondary-color: rgba(33, 37, 41, 0.75); + --bs-secondary-color-rgb: 33, 37, 41; + --bs-secondary-bg: #e9ecef; + --bs-secondary-bg-rgb: 233, 236, 239; + --bs-tertiary-color: rgba(33, 37, 41, 0.5); + --bs-tertiary-color-rgb: 33, 37, 41; + --bs-tertiary-bg: #f8f9fa; + --bs-tertiary-bg-rgb: 248, 249, 250; + --bs-heading-color: inherit; + --bs-link-color: #0d6efd; + --bs-link-color-rgb: 13, 110, 253; + --bs-link-decoration: none; + --bs-link-hover-color: #0a58ca; + --bs-link-hover-color-rgb: 10, 88, 202; + --bs-code-color: #d63384; + --bs-highlight-bg: #fff3cd; + --bs-border-width: 1px; + --bs-border-style: solid; + --bs-border-color: #dee2e6; + --bs-border-color-translucent: rgba(0, 0, 0, 0.175); + --bs-border-radius: 0.375rem; + --bs-border-radius-sm: 0.25rem; + --bs-border-radius-lg: 0.5rem; + --bs-border-radius-xl: 1rem; + --bs-border-radius-xxl: 2rem; + --bs-border-radius-2xl: var(--bs-border-radius-xxl); + --bs-border-radius-pill: 50rem; + --bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); + --bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); + --bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175); + --bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075); + --bs-focus-ring-width: 0.25rem; + --bs-focus-ring-opacity: 0.25; + --bs-focus-ring-color: rgba(49, 187, 107, 0.25); + --bs-form-valid-color: #31bb6b; + --bs-form-valid-border-color: #31bb6b; + --bs-form-invalid-color: #dc3545; + --bs-form-invalid-border-color: #dc3545; +} + +[data-bs-theme='dark'] { + color-scheme: dark; + --bs-body-color: #adb5bd; + --bs-body-color-rgb: 173, 181, 189; + --bs-body-bg: #212529; + --bs-body-bg-rgb: 33, 37, 41; + --bs-emphasis-color: #fff; + --bs-emphasis-color-rgb: 255, 255, 255; + --bs-secondary-color: rgba(173, 181, 189, 0.75); + --bs-secondary-color-rgb: 173, 181, 189; + --bs-secondary-bg: #343a40; + --bs-secondary-bg-rgb: 52, 58, 64; + --bs-tertiary-color: rgba(173, 181, 189, 0.5); + --bs-tertiary-color-rgb: 173, 181, 189; + --bs-tertiary-bg: #2b3035; + --bs-tertiary-bg-rgb: 43, 48, 53; + --bs-primary-text-emphasis: #83d6a6; + --bs-secondary-text-emphasis: darkgray; + --bs-success-text-emphasis: #83d6a6; + --bs-info-text-emphasis: #6edff6; + --bs-warning-text-emphasis: #fed79b; + --bs-danger-text-emphasis: #ea868f; + --bs-light-text-emphasis: #f8f9fa; + --bs-dark-text-emphasis: #dee2e6; + --bs-primary-bg-subtle: #0a2515; + --bs-secondary-bg-subtle: #161616; + --bs-success-bg-subtle: #0a2515; + --bs-info-bg-subtle: #032830; + --bs-warning-bg-subtle: #332612; + --bs-danger-bg-subtle: #2c0b0e; + --bs-light-bg-subtle: #343a40; + --bs-dark-bg-subtle: #1a1d20; + --bs-primary-border-subtle: #1d7040; + --bs-secondary-border-subtle: #434343; + --bs-success-border-subtle: #1d7040; + --bs-info-border-subtle: #087990; + --bs-warning-border-subtle: #987135; + --bs-danger-border-subtle: #842029; + --bs-light-border-subtle: #495057; + --bs-dark-border-subtle: #343a40; + --bs-heading-color: inherit; + --bs-link-color: #83d6a6; + --bs-link-hover-color: #9cdeb8; + --bs-link-color-rgb: 131, 214, 166; + --bs-link-hover-color-rgb: 156, 222, 184; + --bs-code-color: #e685b5; + --bs-border-color: #495057; + --bs-border-color-translucent: rgba(255, 255, 255, 0.15); + --bs-form-valid-color: #75b798; + --bs-form-valid-border-color: #75b798; + --bs-form-invalid-color: #ea868f; + --bs-form-invalid-border-color: #ea868f; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +@media (prefers-reduced-motion: no-preference) { + :root { + scroll-behavior: smooth; + } +} + +body { + margin: 0; + font-family: var(--bs-body-font-family); + font-size: var(--bs-body-font-size); + font-weight: var(--bs-body-font-weight); + line-height: var(--bs-body-line-height); + color: var(--bs-body-color); + text-align: var(--bs-body-text-align); + background-color: var(--bs-body-bg); + -webkit-text-size-adjust: 100%; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +hr { + margin: 1rem 0; + color: inherit; + border: 0; + border-top: var(--bs-border-width) solid; + opacity: 0.25; +} + +h6, +.h6, +h5, +.h5, +h4, +.h4, +h3, +.h3, +h2, +.h2, +h1, +.h1 { + margin-top: 0; + margin-bottom: 0.5rem; + font-weight: 500; + line-height: 1.2; + color: var(--bs-heading-color); +} + +h1, +.h1 { + font-size: calc(1.375rem + 1.5vw); +} +@media (min-width: 1200px) { + h1, + .h1 { + font-size: 2.5rem; + } +} + +h2, +.h2 { + font-size: calc(1.325rem + 0.9vw); +} +@media (min-width: 1200px) { + h2, + .h2 { + font-size: 2rem; + } +} + +h3, +.h3 { + font-size: calc(1.3rem + 0.6vw); +} +@media (min-width: 1200px) { + h3, + .h3 { + font-size: 1.75rem; + } +} + +h4, +.h4 { + font-size: calc(1.275rem + 0.3vw); +} +@media (min-width: 1200px) { + h4, + .h4 { + font-size: 1.5rem; + } +} + +h5, +.h5 { + font-size: 1.25rem; +} + +h6, +.h6 { + font-size: 1rem; +} + +p { + margin-top: 0; + margin-bottom: 1rem; +} + +abbr[title] { + text-decoration: underline dotted; + cursor: help; + text-decoration-skip-ink: none; +} + +address { + margin-bottom: 1rem; + font-style: normal; + line-height: inherit; +} + +ol, +ul { + padding-left: 2rem; +} + +ol, +ul, +dl { + margin-top: 0; + margin-bottom: 1rem; +} + +ol ol, +ul ul, +ol ul, +ul ol { + margin-bottom: 0; +} + +dt { + font-weight: 700; +} + +dd { + margin-bottom: 0.5rem; + margin-left: 0; +} + +blockquote { + margin: 0 0 1rem; +} + +b, +strong { + font-weight: bolder; +} + +small, +.small { + font-size: 0.875em; +} + +mark, +.mark { + padding: 0.1875em; + background-color: var(--bs-highlight-bg); +} + +sub, +sup { + position: relative; + font-size: 0.75em; + line-height: 0; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +a { + color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1)); + text-decoration: none; +} +a:hover { + --bs-link-color-rgb: var(--bs-link-hover-color-rgb); +} + +a:not([href]):not([class]), +a:not([href]):not([class]):hover { + color: inherit; + text-decoration: none; +} + +pre, +code, +kbd, +samp { + font-family: var(--bs-font-monospace); + font-size: 1em; +} + +pre { + display: block; + margin-top: 0; + margin-bottom: 1rem; + overflow: auto; + font-size: 0.875em; +} +pre code { + font-size: inherit; + color: inherit; + word-break: normal; +} + +code { + font-size: 0.875em; + color: var(--bs-code-color); + word-wrap: break-word; +} +a > code { + color: inherit; +} + +kbd { + padding: 0.1875rem 0.375rem; + font-size: 0.875em; + color: var(--bs-body-bg); + background-color: var(--bs-body-color); + border-radius: 0.25rem; +} +kbd kbd { + padding: 0; + font-size: 1em; +} + +figure { + margin: 0 0 1rem; +} + +img, +svg { + vertical-align: middle; +} + +table { + caption-side: bottom; + border-collapse: collapse; +} + +caption { + padding-top: 0.5rem; + padding-bottom: 0.5rem; + color: var(--bs-secondary-color); + text-align: left; +} + +th { + text-align: inherit; + text-align: -webkit-match-parent; +} + +thead, +tbody, +tfoot, +tr, +td, +th { + border-color: inherit; + border-style: solid; + border-width: 0; +} + +label { + display: inline-block; +} + +button { + border-radius: 0; +} + +button:focus:not(:focus-visible) { + outline: 0; +} + +input, +button, +select, +optgroup, +textarea { + margin: 0; + font-family: inherit; + font-size: inherit; + line-height: inherit; +} + +button, +select { + text-transform: none; +} + +[role='button'] { + cursor: pointer; +} + +select { + word-wrap: normal; +} +select:disabled { + opacity: 1; +} + +[list]:not([type='date']):not([type='datetime-local']):not([type='month']):not( + [type='week'] + ):not([type='time'])::-webkit-calendar-picker-indicator { + display: none !important; +} + +button, +[type='button'], +[type='reset'], +[type='submit'] { + -webkit-appearance: button; +} +button:not(:disabled), +[type='button']:not(:disabled), +[type='reset']:not(:disabled), +[type='submit']:not(:disabled) { + cursor: pointer; +} + +::-moz-focus-inner { + padding: 0; + border-style: none; +} + +textarea { + resize: vertical; +} + +fieldset { + min-width: 0; + padding: 0; + margin: 0; + border: 0; +} + +legend { + float: left; + width: 100%; + padding: 0; + margin-bottom: 0.5rem; + font-size: calc(1.275rem + 0.3vw); + line-height: inherit; +} +@media (min-width: 1200px) { + legend { + font-size: 1.5rem; + } +} +legend + * { + clear: left; +} + +::-webkit-datetime-edit-fields-wrapper, +::-webkit-datetime-edit-text, +::-webkit-datetime-edit-minute, +::-webkit-datetime-edit-hour-field, +::-webkit-datetime-edit-day-field, +::-webkit-datetime-edit-month-field, +::-webkit-datetime-edit-year-field { + padding: 0; +} + +::-webkit-inner-spin-button { + height: auto; +} + +[type='search'] { + outline-offset: -2px; + -webkit-appearance: textfield; +} + +/* rtl:raw: + [type="tel"], + [type="url"], + [type="email"], + [type="number"] { + direction: ltr; + } + */ +::-webkit-search-decoration { + -webkit-appearance: none; +} + +::-webkit-color-swatch-wrapper { + padding: 0; +} + +::file-selector-button { + font: inherit; + -webkit-appearance: button; +} + +output { + display: inline-block; +} + +iframe { + border: 0; +} + +summary { + display: list-item; + cursor: pointer; +} + +progress { + vertical-align: baseline; +} + +[hidden] { + display: none !important; +} + +.lead { + font-size: 1.25rem; + font-weight: 300; +} + +.display-1 { + font-size: calc(1.625rem + 4.5vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-1 { + font-size: 5rem; + } +} + +.display-2 { + font-size: calc(1.575rem + 3.9vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-2 { + font-size: 4.5rem; + } +} + +.display-3 { + font-size: calc(1.525rem + 3.3vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-3 { + font-size: 4rem; + } +} + +.display-4 { + font-size: calc(1.475rem + 2.7vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-4 { + font-size: 3.5rem; + } +} + +.display-5 { + font-size: calc(1.425rem + 2.1vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-5 { + font-size: 3rem; + } +} + +.display-6 { + font-size: calc(1.375rem + 1.5vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-6 { + font-size: 2.5rem; + } +} + +.list-unstyled { + padding-left: 0; + list-style: none; +} + +.list-inline { + padding-left: 0; + list-style: none; +} + +.list-inline-item { + display: inline-block; +} +.list-inline-item:not(:last-child) { + margin-right: 0.5rem; +} + +.initialism { + font-size: 0.875em; + text-transform: uppercase; +} + +.blockquote { + margin-bottom: 1rem; + font-size: 1.25rem; +} +.blockquote > :last-child { + margin-bottom: 0; +} + +.blockquote-footer { + margin-top: -1rem; + margin-bottom: 1rem; + font-size: 0.875em; + color: #6c757d; +} +.blockquote-footer::before { + content: '— '; +} + +.img-fluid { + max-width: 100%; + height: auto; +} + +.img-thumbnail { + padding: 0.25rem; + background-color: var(--bs-body-bg); + border: var(--bs-border-width) solid var(--bs-border-color); + border-radius: var(--bs-border-radius); + max-width: 100%; + height: auto; +} + +.figure { + display: inline-block; +} + +.figure-img { + margin-bottom: 0.5rem; + line-height: 1; +} + +.figure-caption { + font-size: 0.875em; + color: var(--bs-secondary-color); +} + +.container, +.container-fluid, +.container-xxl, +.container-xl, +.container-lg, +.container-md, +.container-sm { + --bs-gutter-x: 1.5rem; + --bs-gutter-y: 0; + width: 100%; + padding-right: calc(var(--bs-gutter-x) * 0.5); + padding-left: calc(var(--bs-gutter-x) * 0.5); + margin-right: auto; + margin-left: auto; +} + +@media (min-width: 576px) { + .container-sm, + .container { + max-width: 540px; + } +} +@media (min-width: 768px) { + .container-md, + .container-sm, + .container { + max-width: 720px; + } +} +@media (min-width: 992px) { + .container-lg, + .container-md, + .container-sm, + .container { + max-width: 960px; + } +} +@media (min-width: 1200px) { + .container-xl, + .container-lg, + .container-md, + .container-sm, + .container { + max-width: 1140px; + } +} +@media (min-width: 1400px) { + .container-xxl, + .container-xl, + .container-lg, + .container-md, + .container-sm, + .container { + max-width: 1320px; + } +} +:root { + --bs-breakpoint-xs: 0; + --bs-breakpoint-sm: 576px; + --bs-breakpoint-md: 768px; + --bs-breakpoint-lg: 992px; + --bs-breakpoint-xl: 1200px; + --bs-breakpoint-xxl: 1400px; +} + +.row { + --bs-gutter-x: 1.5rem; + --bs-gutter-y: 0; + display: flex; + flex-wrap: wrap; + margin-top: calc(-1 * var(--bs-gutter-y)); + margin-right: calc(-0.5 * var(--bs-gutter-x)); + margin-left: calc(-0.5 * var(--bs-gutter-x)); +} +.row > * { + flex-shrink: 0; + width: 100%; + max-width: 100%; + padding-right: calc(var(--bs-gutter-x) * 0.5); + padding-left: calc(var(--bs-gutter-x) * 0.5); + margin-top: var(--bs-gutter-y); +} + +.col { + flex: 1 0 0%; +} + +.row-cols-auto > * { + flex: 0 0 auto; + width: auto; +} + +.row-cols-1 > * { + flex: 0 0 auto; + width: 100%; +} + +.row-cols-2 > * { + flex: 0 0 auto; + width: 50%; +} + +.row-cols-3 > * { + flex: 0 0 auto; + width: 33.3333333333%; +} + +.row-cols-4 > * { + flex: 0 0 auto; + width: 25%; +} + +.row-cols-5 > * { + flex: 0 0 auto; + width: 20%; +} + +.row-cols-6 > * { + flex: 0 0 auto; + width: 16.6666666667%; +} + +.col-auto { + flex: 0 0 auto; + width: auto; +} + +.col-1 { + flex: 0 0 auto; + width: 8.33333333%; +} + +.col-2 { + flex: 0 0 auto; + width: 16.66666667%; +} + +.col-3 { + flex: 0 0 auto; + width: 25%; +} + +.col-4 { + flex: 0 0 auto; + width: 33.33333333%; +} + +.col-5 { + flex: 0 0 auto; + width: 41.66666667%; +} + +.col-6 { + flex: 0 0 auto; + width: 50%; +} + +.col-7 { + flex: 0 0 auto; + width: 58.33333333%; +} + +.col-8 { + flex: 0 0 auto; + width: 66.66666667%; +} + +.col-9 { + flex: 0 0 auto; + width: 75%; +} + +.col-10 { + flex: 0 0 auto; + width: 83.33333333%; +} + +.col-11 { + flex: 0 0 auto; + width: 91.66666667%; +} + +.col-12 { + flex: 0 0 auto; + width: 100%; +} + +.offset-1 { + margin-left: 8.33333333%; +} + +.offset-2 { + margin-left: 16.66666667%; +} + +.offset-3 { + margin-left: 25%; +} + +.offset-4 { + margin-left: 33.33333333%; +} + +.offset-5 { + margin-left: 41.66666667%; +} + +.offset-6 { + margin-left: 50%; +} + +.offset-7 { + margin-left: 58.33333333%; +} + +.offset-8 { + margin-left: 66.66666667%; +} + +.offset-9 { + margin-left: 75%; +} + +.offset-10 { + margin-left: 83.33333333%; +} + +.offset-11 { + margin-left: 91.66666667%; +} + +.g-0, +.gx-0 { + --bs-gutter-x: 0; +} + +.g-0, +.gy-0 { + --bs-gutter-y: 0; +} + +.g-1, +.gx-1 { + --bs-gutter-x: 0.25rem; +} + +.g-1, +.gy-1 { + --bs-gutter-y: 0.25rem; +} + +.g-2, +.gx-2 { + --bs-gutter-x: 0.5rem; +} + +.g-2, +.gy-2 { + --bs-gutter-y: 0.5rem; +} + +.g-3, +.gx-3 { + --bs-gutter-x: 1rem; +} + +.g-3, +.gy-3 { + --bs-gutter-y: 1rem; +} + +.g-4, +.gx-4 { + --bs-gutter-x: 1.5rem; +} + +.g-4, +.gy-4 { + --bs-gutter-y: 1.5rem; +} + +.g-5, +.gx-5 { + --bs-gutter-x: 3rem; +} + +.g-5, +.gy-5 { + --bs-gutter-y: 3rem; +} + +@media (min-width: 576px) { + .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; + --bs-table-color-state: initial; + --bs-table-bg-state: initial; + --bs-table-color: var(--bs-body-color); + --bs-table-bg: var(--bs-body-bg); + --bs-table-border-color: var(--bs-border-color); + --bs-table-accent-bg: transparent; + --bs-table-striped-color: var(--bs-body-color); + --bs-table-striped-bg: rgba(0, 0, 0, 0.05); + --bs-table-active-color: var(--bs-body-color); + --bs-table-active-bg: rgba(0, 0, 0, 0.1); + --bs-table-hover-color: var(--bs-body-color); + --bs-table-hover-bg: rgba(0, 0, 0, 0.075); + width: 100%; + margin-bottom: 1rem; + vertical-align: top; + border-color: var(--bs-table-border-color); +} +.table > :not(caption) > * > * { + padding: 0.5rem 0.5rem; + color: var( + --bs-table-color-state, + var(--bs-table-color-type, var(--bs-table-color)) + ); + background-color: var(--bs-table-bg); + border-bottom-width: var(--bs-border-width); + 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; +} + +.table-group-divider { + border-top: calc(var(--bs-border-width) * 2) solid currentcolor; +} + +.caption-top { + caption-side: top; +} + +.table-sm > :not(caption) > * > * { + padding: 0.25rem 0.25rem; +} + +.table-bordered > :not(caption) > * { + border-width: var(--bs-border-width) 0; +} +.table-bordered > :not(caption) > * > * { + border-width: 0 var(--bs-border-width); +} + +.table-borderless > :not(caption) > * > * { + border-bottom-width: 0; +} +.table-borderless > :not(:first-child) { + border-top-width: 0; +} + +.table-striped > tbody > tr:nth-of-type(odd) > * { + --bs-table-color-type: var(--bs-table-striped-color); + --bs-table-bg-type: var(--bs-table-striped-bg); +} + +.table-striped-columns > :not(caption) > tr > :nth-child(even) { + --bs-table-color-type: var(--bs-table-striped-color); + --bs-table-bg-type: var(--bs-table-striped-bg); +} + +.table-active { + --bs-table-color-state: var(--bs-table-active-color); + --bs-table-bg-state: var(--bs-table-active-bg); +} + +.table-hover > tbody > tr:hover > * { + --bs-table-color-state: var(--bs-table-hover-color); + --bs-table-bg-state: var(--bs-table-hover-bg); +} + +.table-primary { + --bs-table-color: #000; + --bs-table-bg: #d6f1e1; + --bs-table-border-color: #c1d9cb; + --bs-table-striped-bg: #cbe5d6; + --bs-table-striped-color: #000; + --bs-table-active-bg: #c1d9cb; + --bs-table-active-color: #000; + --bs-table-hover-bg: #c6dfd0; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-secondary { + --bs-table-color: #000; + --bs-table-bg: #e2e2e2; + --bs-table-border-color: #cbcbcb; + --bs-table-striped-bg: #d7d7d7; + --bs-table-striped-color: #000; + --bs-table-active-bg: #cbcbcb; + --bs-table-active-color: #000; + --bs-table-hover-bg: #d1d1d1; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-success { + --bs-table-color: #000; + --bs-table-bg: #d6f1e1; + --bs-table-border-color: #c1d9cb; + --bs-table-striped-bg: #cbe5d6; + --bs-table-striped-color: #000; + --bs-table-active-bg: #c1d9cb; + --bs-table-active-color: #000; + --bs-table-hover-bg: #c6dfd0; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-info { + --bs-table-color: #000; + --bs-table-bg: #cff4fc; + --bs-table-border-color: #badce3; + --bs-table-striped-bg: #c5e8ef; + --bs-table-striped-color: #000; + --bs-table-active-bg: #badce3; + --bs-table-active-color: #000; + --bs-table-hover-bg: #bfe2e9; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-warning { + --bs-table-color: #000; + --bs-table-bg: #fff2de; + --bs-table-border-color: #e6dac8; + --bs-table-striped-bg: #f2e6d3; + --bs-table-striped-color: #000; + --bs-table-active-bg: #e6dac8; + --bs-table-active-color: #000; + --bs-table-hover-bg: #ece0cd; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-danger { + --bs-table-color: #000; + --bs-table-bg: #f8d7da; + --bs-table-border-color: #dfc2c4; + --bs-table-striped-bg: #eccccf; + --bs-table-striped-color: #000; + --bs-table-active-bg: #dfc2c4; + --bs-table-active-color: #000; + --bs-table-hover-bg: #e5c7ca; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-light { + --bs-table-color: #000; + --bs-table-bg: #f8f9fa; + --bs-table-border-color: #dfe0e1; + --bs-table-striped-bg: #ecedee; + --bs-table-striped-color: #000; + --bs-table-active-bg: #dfe0e1; + --bs-table-active-color: #000; + --bs-table-hover-bg: #e5e6e7; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-dark { + --bs-table-color: #fff; + --bs-table-bg: #212529; + --bs-table-border-color: #373b3e; + --bs-table-striped-bg: #2c3034; + --bs-table-striped-color: #fff; + --bs-table-active-bg: #373b3e; + --bs-table-active-color: #fff; + --bs-table-hover-bg: #323539; + --bs-table-hover-color: #fff; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-responsive { + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} + +@media (max-width: 575.98px) { + .table-responsive-sm { + overflow-x: auto; + -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; +} + +.col-form-label { + padding-top: 0.7rem; + padding-bottom: 0.7rem; + margin-bottom: 0; + font-size: inherit; + line-height: 1.5; +} + +.col-form-label-lg { + padding-top: 0.5rem; + padding-bottom: 0.5rem; + font-size: 1.25rem; +} + +.col-form-label-sm { + padding-top: 0.25rem; + padding-bottom: 0.25rem; + font-size: 0.875rem; +} + +.form-text { + margin-top: 0.25rem; + font-size: 0.875em; + color: var(--bs-secondary-color); +} + +.form-control { + display: block; + width: 100%; + padding: 0.7rem 1rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: var(--bs-body-color); + background-color: #f2f2f2; + background-clip: padding-box; + border: 1px solid var(--bs-border-color); + appearance: none; + border-radius: var(--bs-border-radius); + transition: + 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; + border-color: #98ddb5; + 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; + margin-inline-end: 1rem; + color: var(--bs-body-color); + background-color: var(--bs-tertiary-bg); + pointer-events: none; + border-color: inherit; + border-style: solid; + border-width: 0; + border-inline-end-width: 0; + border-radius: 0; + transition: + color 0.15s ease-in-out, + background-color 0.15s ease-in-out, + 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); +} + +.form-control-plaintext { + display: block; + width: 100%; + padding: 0.7rem 0; + margin-bottom: 0; + line-height: 1.5; + color: var(--bs-body-color); + background-color: transparent; + 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; + padding-left: 0; +} + +.form-control-sm { + min-height: calc(1.5em + 0.5rem + calc(0 * 2)); + padding: 0.25rem 0.5rem; + 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; + margin-inline-end: 0.5rem; +} + +.form-control-lg { + min-height: calc(1.5em + 1rem + calc(0 * 2)); + padding: 0.5rem 1rem; + 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; + margin-inline-end: 1rem; +} + +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)); +} + +.form-control-color { + width: 3rem; + 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)); +} + +.form-select { + --bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"); + display: block; + width: 100%; + padding: 0.7rem 3rem 0.7rem 1rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: var(--bs-body-color); + background-color: #f2f2f2; + background-image: var(--bs-form-select-bg-img), + var(--bs-form-select-bg-icon, none); + background-repeat: no-repeat; + background-position: right 1rem center; + background-size: 16px 12px; + border: 0 solid var(--bs-border-color); + border-radius: var(--bs-border-radius); + transition: + border-color 0.15s ease-in-out, + 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); +} + +.form-select-sm { + padding-top: 0.25rem; + padding-bottom: 0.25rem; + padding-left: 0.5rem; + font-size: 0.875rem; + border-radius: var(--bs-border-radius-sm); +} + +.form-select-lg { + padding-top: 0.5rem; + padding-bottom: 0.5rem; + padding-left: 1rem; + font-size: 1.25rem; + border-radius: var(--bs-border-radius-lg); +} + +[data-bs-theme='dark'] .form-select { + --bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23adb5bd' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"); +} + +.form-check { + display: block; + min-height: 1.5rem; + padding-left: 1.5em; + margin-bottom: 0.125rem; +} +.form-check .form-check-input { + float: left; + margin-left: -1.5em; +} + +.form-check-reverse { + padding-right: 1.5em; + padding-left: 0; + text-align: right; +} +.form-check-reverse .form-check-input { + float: right; + margin-right: -1.5em; + margin-left: 0; +} + +.form-check-input { + --bs-form-check-bg: #f2f2f2; + width: 1.3em; + height: 1.3em; + margin-top: 0.25em; + vertical-align: top; + background-color: var(--bs-form-check-bg); + background-image: var(--bs-form-check-bg-image); + background-repeat: no-repeat; + background-position: center; + background-size: contain; + border: var(--bs-border-width) solid var(--bs-border-color); + 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; + opacity: 0.5; +} + +.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; + margin-left: -2.5em; + background-image: var(--bs-form-switch-bg); + background-position: left center; + 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; +} + +.form-check-inline { + display: inline-block; + margin-right: 1rem; +} + +.btn-check { + position: absolute; + clip: rect(0, 0, 0, 0); + pointer-events: none; +} +.btn-check[disabled] + .btn, +.btn-check:disabled + .btn { + pointer-events: none; + filter: none; + opacity: 0.65; +} + +[data-bs-theme='dark'] + .form-switch + .form-check-input:not(:checked):not(: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='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e"); +} + +.form-range { + width: 100%; + height: 1.5rem; + padding: 0; + 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; + margin-top: -0.25rem; + background-color: #31bb6b; + border: 0; + border-radius: 1rem; + transition: + background-color 0.15s ease-in-out, + border-color 0.15s ease-in-out, + 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; + color: transparent; + cursor: pointer; + background-color: var(--bs-tertiary-bg); + border-color: transparent; + border-radius: 1rem; +} +.form-range::-moz-range-thumb { + width: 1rem; + height: 1rem; + background-color: #31bb6b; + border: 0; + border-radius: 1rem; + transition: + background-color 0.15s ease-in-out, + border-color 0.15s ease-in-out, + 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; + color: transparent; + cursor: pointer; + background-color: var(--bs-tertiary-bg); + 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); +} + +.form-floating { + position: relative; +} +.form-floating > .form-control, +.form-floating > .form-control-plaintext, +.form-floating > .form-select { + height: calc(3.5rem + calc(0 * 2)); + min-height: calc(3.5rem + calc(0 * 2)); + line-height: 1.25; +} +.form-floating > label { + position: absolute; + top: 0; + left: 0; + z-index: 2; + height: 100%; + padding: 1rem 1rem; + overflow: hidden; + text-align: start; + text-overflow: ellipsis; + white-space: nowrap; + pointer-events: none; + border: 0 solid transparent; + transform-origin: 0 0; + transition: + 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, +.form-floating > .form-control-plaintext:not(:placeholder-shown) { + 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, +.form-floating > .form-select ~ label { + 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, +.form-floating > .form-select ~ label::after { + position: absolute; + inset: 1rem 0.5rem; + z-index: -1; + height: 1.5em; + content: ''; + 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); +} + +.input-group { + position: relative; + display: flex; + flex-wrap: wrap; + align-items: stretch; + width: 100%; +} +.input-group > .form-control, +.input-group > .form-select, +.input-group > .form-floating { + position: relative; + flex: 1 1 auto; + 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; +} + +.input-group-text { + display: flex; + align-items: center; + padding: 0.7rem 1rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: var(--bs-body-color); + text-align: center; + white-space: nowrap; + background-color: var(--bs-tertiary-bg); + border: 0 solid var(--bs-border-color); + border-radius: var(--bs-border-radius); +} + +.input-group-lg > .form-control, +.input-group-lg > .form-select, +.input-group-lg > .input-group-text, +.input-group-lg > .btn { + padding: 0.5rem 1rem; + font-size: 1.25rem; + border-radius: var(--bs-border-radius-lg); +} + +.input-group-sm > .form-control, +.input-group-sm > .form-select, +.input-group-sm > .input-group-text, +.input-group-sm > .btn { + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + border-radius: var(--bs-border-radius-sm); +} + +.input-group-lg > .form-select, +.input-group-sm > .form-select { + padding-right: 4rem; +} + +.input-group:not(.has-validation) + > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not( + .form-floating + ), +.input-group:not(.has-validation) > .dropdown-toggle:nth-last-child(n + 3), +.input-group:not(.has-validation) + > .form-floating:not(:last-child) + > .form-control, +.input-group:not(.has-validation) + > .form-floating:not(:last-child) + > .form-select { + 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 + ), +.input-group.has-validation > .dropdown-toggle:nth-last-child(n + 4), +.input-group.has-validation + > .form-floating:nth-last-child(n + 3) + > .form-control, +.input-group.has-validation + > .form-floating:nth-last-child(n + 3) + > .form-select { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.input-group + > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not( + .valid-feedback + ):not(.invalid-tooltip):not(.invalid-feedback) { + margin-left: calc(0 * -1); + 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; + border-bottom-left-radius: 0; +} + +.valid-feedback { + display: none; + width: 100%; + margin-top: 0.25rem; + font-size: 0.875em; + color: var(--bs-form-valid-color); +} + +.valid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: 0.25rem 0.5rem; + margin-top: 0.1rem; + font-size: 0.875rem; + color: #fff; + background-color: var(--bs-success); + border-radius: var(--bs-border-radius); +} + +.was-validated :valid ~ .valid-feedback, +.was-validated :valid ~ .valid-tooltip, +.is-valid ~ .valid-feedback, +.is-valid ~ .valid-tooltip { + display: block; +} + +.was-validated .form-control:valid, +.form-control.is-valid { + border-color: var(--bs-form-valid-border-color); + padding-right: calc(1.5em + 1.4rem); + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2331bb6b' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + 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); + box-shadow: 0 0 0 0.25rem rgba(var(--bs-success-rgb), 0.25); +} + +.was-validated textarea.form-control:valid, +textarea.form-control.is-valid { + padding-right: calc(1.5em + 1.4rem); + background-position: top calc(0.375em + 0.35rem) right calc(0.375em + 0.35rem); +} + +.was-validated .form-select: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]), +.form-select.is-valid:not([multiple])[size='1'] { + --bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2331bb6b' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e"); + padding-right: 5.5rem; + background-position: + right 1rem center, + center right 3rem; + background-size: + 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); + box-shadow: 0 0 0 0.25rem rgba(var(--bs-success-rgb), 0.25); +} + +.was-validated .form-control-color:valid, +.form-control-color.is-valid { + width: calc(3rem + calc(1.5em + 1.4rem)); +} + +.was-validated .form-check-input: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); +} + +.form-check-inline .form-check-input ~ .valid-feedback { + margin-left: 0.5em; +} + +.was-validated .input-group > .form-control:not(:focus):valid, +.input-group > .form-control:not(:focus).is-valid, +.was-validated .input-group > .form-select:not(:focus):valid, +.input-group > .form-select:not(:focus).is-valid, +.was-validated .input-group > .form-floating:not(:focus-within):valid, +.input-group > .form-floating:not(:focus-within).is-valid { + z-index: 3; +} + +.invalid-feedback { + display: none; + width: 100%; + margin-top: 0.25rem; + font-size: 0.875em; + color: var(--bs-form-invalid-color); +} + +.invalid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: 0.25rem 0.5rem; + margin-top: 0.1rem; + font-size: 0.875rem; + color: #fff; + background-color: var(--bs-danger); + border-radius: var(--bs-border-radius); +} + +.was-validated :invalid ~ .invalid-feedback, +.was-validated :invalid ~ .invalid-tooltip, +.is-invalid ~ .invalid-feedback, +.is-invalid ~ .invalid-tooltip { + display: block; +} + +.was-validated .form-control:invalid, +.form-control.is-invalid { + border-color: var(--bs-form-invalid-border-color); + padding-right: calc(1.5em + 1.4rem); + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + 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); + box-shadow: 0 0 0 0.25rem rgba(var(--bs-danger-rgb), 0.25); +} + +.was-validated textarea.form-control:invalid, +textarea.form-control.is-invalid { + padding-right: calc(1.5em + 1.4rem); + background-position: top calc(0.375em + 0.35rem) right calc(0.375em + 0.35rem); +} + +.was-validated .form-select: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]), +.form-select.is-invalid:not([multiple])[size='1'] { + --bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e"); + padding-right: 5.5rem; + background-position: + right 1rem center, + center right 3rem; + background-size: + 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); + box-shadow: 0 0 0 0.25rem rgba(var(--bs-danger-rgb), 0.25); +} + +.was-validated .form-control-color:invalid, +.form-control-color.is-invalid { + width: calc(3rem + calc(1.5em + 1.4rem)); +} + +.was-validated .form-check-input: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); +} + +.form-check-inline .form-check-input ~ .invalid-feedback { + margin-left: 0.5em; +} + +.was-validated .input-group > .form-control:not(:focus):invalid, +.input-group > .form-control:not(:focus).is-invalid, +.was-validated .input-group > .form-select:not(:focus):invalid, +.input-group > .form-select:not(:focus).is-invalid, +.was-validated .input-group > .form-floating:not(:focus-within):invalid, +.input-group > .form-floating:not(:focus-within).is-invalid { + z-index: 4; +} + +.btn { + --bs-btn-padding-x: 1rem; + --bs-btn-padding-y: 0.7rem; + --bs-btn-font-family: ; + --bs-btn-font-size: 1rem; + --bs-btn-font-weight: 400; + --bs-btn-line-height: 1.5; + --bs-btn-color: var(--bs-body-color); + --bs-btn-bg: transparent; + --bs-btn-border-width: var(--bs-border-width); + --bs-btn-border-color: transparent; + --bs-btn-border-radius: var(--bs-border-radius); + --bs-btn-hover-border-color: transparent; + --bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), + 0 1px 1px rgba(0, 0, 0, 0.075); + --bs-btn-disabled-opacity: 0.65; + --bs-btn-focus-box-shadow: 0 0 0 0.25rem + rgba(var(--bs-btn-focus-shadow-rgb), 0.5); + display: inline-block; + padding: var(--bs-btn-padding-y) var(--bs-btn-padding-x); + font-family: var(--bs-btn-font-family); + font-size: var(--bs-btn-font-size); + font-weight: var(--bs-btn-font-weight); + line-height: var(--bs-btn-line-height); + color: var(--bs-btn-color); + text-align: center; + vertical-align: middle; + cursor: pointer; + user-select: none; + border: var(--bs-btn-border-width) solid var(--bs-btn-border-color); + border-radius: var(--bs-btn-border-radius); + background-color: var(--bs-btn-bg); + transition: + color 0.15s ease-in-out, + background-color 0.15s ease-in-out, + 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); + border-color: var(--bs-btn-hover-border-color); + 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, +.btn.active, +.btn.show { + color: var(--bs-btn-active-color); + 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, +.btn.active:focus-visible, +.btn.show:focus-visible { + box-shadow: var(--bs-btn-focus-box-shadow); +} +.btn:disabled, +.btn.disabled, +fieldset:disabled .btn { + color: var(--bs-btn-disabled-color); + pointer-events: none; + background-color: var(--bs-btn-disabled-bg); + border-color: var(--bs-btn-disabled-border-color); + opacity: var(--bs-btn-disabled-opacity); +} + +.btn-primary { + --bs-btn-color: #000; + --bs-btn-bg: #31bb6b; + --bs-btn-border-color: #31bb6b; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #50c581; + --bs-btn-hover-border-color: #46c27a; + --bs-btn-focus-shadow-rgb: 42, 159, 91; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #5ac989; + --bs-btn-active-border-color: #46c27a; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #31bb6b; + --bs-btn-disabled-border-color: #31bb6b; +} + +.btn-secondary { + --bs-btn-color: #fff; + --bs-btn-bg: #707070; + --bs-btn-border-color: #707070; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #5f5f5f; + --bs-btn-hover-border-color: #5a5a5a; + --bs-btn-focus-shadow-rgb: 133, 133, 133; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #5a5a5a; + --bs-btn-active-border-color: #545454; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #707070; + --bs-btn-disabled-border-color: #707070; +} + +.btn-success { + --bs-btn-color: #000; + --bs-btn-bg: #31bb6b; + --bs-btn-border-color: #31bb6b; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #50c581; + --bs-btn-hover-border-color: #46c27a; + --bs-btn-focus-shadow-rgb: 42, 159, 91; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #5ac989; + --bs-btn-active-border-color: #46c27a; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #31bb6b; + --bs-btn-disabled-border-color: #31bb6b; +} + +.btn-info { + --bs-btn-color: #000; + --bs-btn-bg: #0dcaf0; + --bs-btn-border-color: #0dcaf0; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #31d2f2; + --bs-btn-hover-border-color: #25cff2; + --bs-btn-focus-shadow-rgb: 11, 172, 204; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #3dd5f3; + --bs-btn-active-border-color: #25cff2; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #0dcaf0; + --bs-btn-disabled-border-color: #0dcaf0; +} + +.btn-warning { + --bs-btn-color: #000; + --bs-btn-bg: #febc59; + --bs-btn-border-color: #febc59; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #fec672; + --bs-btn-hover-border-color: #fec36a; + --bs-btn-focus-shadow-rgb: 216, 160, 76; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #fec97a; + --bs-btn-active-border-color: #fec36a; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #febc59; + --bs-btn-disabled-border-color: #febc59; +} + +.btn-danger { + --bs-btn-color: #fff; + --bs-btn-bg: #dc3545; + --bs-btn-border-color: #dc3545; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #bb2d3b; + --bs-btn-hover-border-color: #b02a37; + --bs-btn-focus-shadow-rgb: 225, 83, 97; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #b02a37; + --bs-btn-active-border-color: #a52834; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #dc3545; + --bs-btn-disabled-border-color: #dc3545; +} + +.btn-light { + --bs-btn-color: #000; + --bs-btn-bg: #f8f9fa; + --bs-btn-border-color: #f8f9fa; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #d3d4d5; + --bs-btn-hover-border-color: #c6c7c8; + --bs-btn-focus-shadow-rgb: 211, 212, 213; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #c6c7c8; + --bs-btn-active-border-color: #babbbc; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #f8f9fa; + --bs-btn-disabled-border-color: #f8f9fa; +} + +.btn-dark { + --bs-btn-color: #fff; + --bs-btn-bg: #212529; + --bs-btn-border-color: #212529; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #424649; + --bs-btn-hover-border-color: #373b3e; + --bs-btn-focus-shadow-rgb: 66, 70, 73; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #4d5154; + --bs-btn-active-border-color: #373b3e; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #212529; + --bs-btn-disabled-border-color: #212529; +} + +.btn-outline-primary { + --bs-btn-color: #31bb6b; + --bs-btn-border-color: #31bb6b; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #31bb6b; + --bs-btn-hover-border-color: #31bb6b; + --bs-btn-focus-shadow-rgb: 49, 187, 107; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #31bb6b; + --bs-btn-active-border-color: #31bb6b; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #31bb6b; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #31bb6b; + --bs-gradient: none; +} + +.btn-outline-secondary { + --bs-btn-color: #707070; + --bs-btn-border-color: #707070; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #707070; + --bs-btn-hover-border-color: #707070; + --bs-btn-focus-shadow-rgb: 112, 112, 112; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #707070; + --bs-btn-active-border-color: #707070; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #707070; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #707070; + --bs-gradient: none; +} + +.btn-outline-success { + --bs-btn-color: #31bb6b; + --bs-btn-border-color: #31bb6b; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #31bb6b; + --bs-btn-hover-border-color: #31bb6b; + --bs-btn-focus-shadow-rgb: 49, 187, 107; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #31bb6b; + --bs-btn-active-border-color: #31bb6b; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #31bb6b; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #31bb6b; + --bs-gradient: none; +} + +.btn-outline-info { + --bs-btn-color: #0dcaf0; + --bs-btn-border-color: #0dcaf0; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #0dcaf0; + --bs-btn-hover-border-color: #0dcaf0; + --bs-btn-focus-shadow-rgb: 13, 202, 240; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #0dcaf0; + --bs-btn-active-border-color: #0dcaf0; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #0dcaf0; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #0dcaf0; + --bs-gradient: none; +} + +.btn-outline-warning { + --bs-btn-color: #febc59; + --bs-btn-border-color: #febc59; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #febc59; + --bs-btn-hover-border-color: #febc59; + --bs-btn-focus-shadow-rgb: 254, 188, 89; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #febc59; + --bs-btn-active-border-color: #febc59; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #febc59; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #febc59; + --bs-gradient: none; +} + +.btn-outline-danger { + --bs-btn-color: #dc3545; + --bs-btn-border-color: #dc3545; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #dc3545; + --bs-btn-hover-border-color: #dc3545; + --bs-btn-focus-shadow-rgb: 220, 53, 69; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #dc3545; + --bs-btn-active-border-color: #dc3545; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #dc3545; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #dc3545; + --bs-gradient: none; +} + +.btn-outline-light { + --bs-btn-color: #f8f9fa; + --bs-btn-border-color: #f8f9fa; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #f8f9fa; + --bs-btn-hover-border-color: #f8f9fa; + --bs-btn-focus-shadow-rgb: 248, 249, 250; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #f8f9fa; + --bs-btn-active-border-color: #f8f9fa; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #f8f9fa; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #f8f9fa; + --bs-gradient: none; +} + +.btn-outline-dark { + --bs-btn-color: #212529; + --bs-btn-border-color: #212529; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #212529; + --bs-btn-hover-border-color: #212529; + --bs-btn-focus-shadow-rgb: 33, 37, 41; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #212529; + --bs-btn-active-border-color: #212529; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #212529; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #212529; + --bs-gradient: none; +} + +.btn-link { + --bs-btn-font-weight: 400; + --bs-btn-color: var(--bs-link-color); + --bs-btn-bg: transparent; + --bs-btn-border-color: transparent; + --bs-btn-hover-color: var(--bs-link-hover-color); + --bs-btn-hover-border-color: transparent; + --bs-btn-active-color: var(--bs-link-hover-color); + --bs-btn-active-border-color: transparent; + --bs-btn-disabled-color: #6c757d; + --bs-btn-disabled-border-color: transparent; + --bs-btn-box-shadow: 0 0 0 #000; + --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); +} + +.btn-lg, +.btn-group-lg > .btn { + --bs-btn-padding-y: 0.5rem; + --bs-btn-padding-x: 1rem; + --bs-btn-font-size: 1.25rem; + --bs-btn-border-radius: var(--bs-border-radius-lg); +} + +.btn-sm, +.btn-group-sm > .btn { + --bs-btn-padding-y: 0.25rem; + --bs-btn-padding-x: 0.5rem; + --bs-btn-font-size: 0.875rem; + --bs-btn-border-radius: var(--bs-border-radius-sm); +} + +.fade { + transition: opacity 0.15s linear; +} +@media (prefers-reduced-motion: reduce) { + .fade { + transition: none; + } +} +.fade:not(.show) { + opacity: 0; +} + +.collapse:not(.show) { + display: none; +} + +.collapsing { + height: 0; + 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; + } +} + +.dropup, +.dropend, +.dropdown, +.dropstart, +.dropup-center, +.dropdown-center { + position: relative; +} + +.dropdown-toggle { + white-space: nowrap; +} +.dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ''; + border-top: 0.3em solid; + border-right: 0.3em solid transparent; + border-bottom: 0; + border-left: 0.3em solid transparent; +} +.dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropdown-menu { + --bs-dropdown-zindex: 1000; + --bs-dropdown-min-width: 10rem; + --bs-dropdown-padding-x: 0; + --bs-dropdown-padding-y: 0.5rem; + --bs-dropdown-spacer: 0.125rem; + --bs-dropdown-font-size: 1rem; + --bs-dropdown-color: var(--bs-body-color); + --bs-dropdown-bg: var(--bs-body-bg); + --bs-dropdown-border-color: var(--bs-border-color-translucent); + --bs-dropdown-border-radius: var(--bs-border-radius); + --bs-dropdown-border-width: var(--bs-border-width); + --bs-dropdown-inner-border-radius: calc( + var(--bs-border-radius) - var(--bs-border-width) + ); + --bs-dropdown-divider-bg: var(--bs-border-color-translucent); + --bs-dropdown-divider-margin-y: 0.5rem; + --bs-dropdown-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); + --bs-dropdown-link-color: var(--bs-body-color); + --bs-dropdown-link-hover-color: var(--bs-body-color); + --bs-dropdown-link-hover-bg: var(--bs-tertiary-bg); + --bs-dropdown-link-active-color: #fff; + --bs-dropdown-link-active-bg: #31bb6b; + --bs-dropdown-link-disabled-color: var(--bs-tertiary-color); + --bs-dropdown-item-padding-x: 1rem; + --bs-dropdown-item-padding-y: 0.25rem; + --bs-dropdown-header-color: #6c757d; + --bs-dropdown-header-padding-x: 1rem; + --bs-dropdown-header-padding-y: 0.5rem; + position: absolute; + z-index: var(--bs-dropdown-zindex); + display: none; + min-width: var(--bs-dropdown-min-width); + padding: var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x); + margin: 0; + font-size: var(--bs-dropdown-font-size); + color: var(--bs-dropdown-color); + text-align: left; + list-style: none; + background-color: var(--bs-dropdown-bg); + background-clip: padding-box; + 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; + margin-top: var(--bs-dropdown-spacer); +} + +.dropdown-menu-start { + --bs-position: start; +} +.dropdown-menu-start[data-bs-popper] { + right: auto; + left: 0; +} + +.dropdown-menu-end { + --bs-position: end; +} +.dropdown-menu-end[data-bs-popper] { + right: 0; + left: auto; +} + +@media (min-width: 576px) { + .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; + vertical-align: 0.255em; + content: ''; + border-top: 0; + border-right: 0.3em solid transparent; + border-bottom: 0.3em solid; + border-left: 0.3em solid transparent; +} +.dropup .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropend .dropdown-menu[data-bs-popper] { + top: 0; + right: auto; + left: 100%; + margin-top: 0; + margin-left: var(--bs-dropdown-spacer); +} +.dropend .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ''; + border-top: 0.3em solid transparent; + border-right: 0; + 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; +} + +.dropstart .dropdown-menu[data-bs-popper] { + top: 0; + right: 100%; + left: auto; + 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; + vertical-align: 0.255em; + content: ''; + border-top: 0.3em solid transparent; + 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; +} + +.dropdown-divider { + height: 0; + margin: var(--bs-dropdown-divider-margin-y) 0; + overflow: hidden; + border-top: 1px solid var(--bs-dropdown-divider-bg); + opacity: 1; +} + +.dropdown-item { + display: block; + width: 100%; + padding: var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x); + clear: both; + font-weight: 400; + color: var(--bs-dropdown-link-color); + text-align: inherit; + white-space: nowrap; + background-color: transparent; + 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); + pointer-events: none; + background-color: transparent; +} + +.dropdown-menu.show { + display: block; +} + +.dropdown-header { + display: block; + padding: var(--bs-dropdown-header-padding-y) + var(--bs-dropdown-header-padding-x); + margin-bottom: 0; + font-size: 0.875rem; + color: var(--bs-dropdown-header-color); + white-space: nowrap; +} + +.dropdown-item-text { + display: block; + padding: var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x); + color: var(--bs-dropdown-link-color); +} + +.dropdown-menu-dark { + --bs-dropdown-color: #dee2e6; + --bs-dropdown-bg: #343a40; + --bs-dropdown-border-color: var(--bs-border-color-translucent); + --bs-dropdown-box-shadow: ; + --bs-dropdown-link-color: #dee2e6; + --bs-dropdown-link-hover-color: #fff; + --bs-dropdown-divider-bg: var(--bs-border-color-translucent); + --bs-dropdown-link-hover-bg: rgba(255, 255, 255, 0.15); + --bs-dropdown-link-active-color: #fff; + --bs-dropdown-link-active-bg: #31bb6b; + --bs-dropdown-link-disabled-color: #adb5bd; + --bs-dropdown-header-color: #adb5bd; +} + +.btn-group, +.btn-group-vertical { + position: relative; + 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, +.btn-group > .btn:focus, +.btn-group > .btn:active, +.btn-group > .btn.active, +.btn-group-vertical > .btn-check:checked + .btn, +.btn-group-vertical > .btn-check:focus + .btn, +.btn-group-vertical > .btn:hover, +.btn-group-vertical > .btn:focus, +.btn-group-vertical > .btn:active, +.btn-group-vertical > .btn.active { + z-index: 1; +} + +.btn-toolbar { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; +} +.btn-toolbar .input-group { + width: auto; +} + +.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 { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.dropdown-toggle-split { + 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; +} + +.btn-sm + .dropdown-toggle-split, +.btn-group-sm > .btn + .dropdown-toggle-split { + padding-right: 0.375rem; + padding-left: 0.375rem; +} + +.btn-lg + .dropdown-toggle-split, +.btn-group-lg > .btn + .dropdown-toggle-split { + padding-right: 0.75rem; + padding-left: 0.75rem; +} + +.btn-group-vertical { + flex-direction: column; + 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; + border-top-right-radius: 0; +} + +.nav { + --bs-nav-link-padding-x: 1rem; + --bs-nav-link-padding-y: 0.5rem; + --bs-nav-link-font-weight: ; + --bs-nav-link-color: var(--bs-link-color); + --bs-nav-link-hover-color: var(--bs-link-hover-color); + --bs-nav-link-disabled-color: var(--bs-secondary-color); + display: flex; + flex-wrap: wrap; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.nav-link { + display: block; + padding: var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x); + font-size: var(--bs-nav-link-font-size); + font-weight: var(--bs-nav-link-font-weight); + color: var(--bs-nav-link-color); + background: none; + border: 0; + transition: + color 0.15s ease-in-out, + 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; + cursor: default; +} + +.nav-tabs { + --bs-nav-tabs-border-width: var(--bs-border-width); + --bs-nav-tabs-border-color: var(--bs-border-color); + --bs-nav-tabs-border-radius: var(--bs-border-radius); + --bs-nav-tabs-link-hover-border-color: var(--bs-secondary-bg) + var(--bs-secondary-bg) var(--bs-border-color); + --bs-nav-tabs-link-active-color: var(--bs-emphasis-color); + --bs-nav-tabs-link-active-bg: var(--bs-body-bg); + --bs-nav-tabs-link-active-border-color: var(--bs-border-color) + var(--bs-border-color) var(--bs-body-bg); + 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; + border-top-right-radius: 0; +} + +.nav-pills { + --bs-nav-pills-border-radius: var(--bs-border-radius); + --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); + background-color: var(--bs-nav-pills-link-active-bg); +} + +.nav-underline { + --bs-nav-underline-gap: 1rem; + --bs-nav-underline-border-width: 0.125rem; + --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; + color: var(--bs-nav-underline-link-active-color); + border-bottom-color: currentcolor; +} + +.nav-fill > .nav-link, +.nav-fill .nav-item { + flex: 1 1 auto; + text-align: center; +} + +.nav-justified > .nav-link, +.nav-justified .nav-item { + flex-basis: 0; + flex-grow: 1; + text-align: center; +} + +.nav-fill .nav-item .nav-link, +.nav-justified .nav-item .nav-link { + width: 100%; +} + +.tab-content > .tab-pane { + display: none; +} +.tab-content > .active { + display: block; +} + +.navbar { + --bs-navbar-padding-x: 0; + --bs-navbar-padding-y: 0.5rem; + --bs-navbar-color: rgba(var(--bs-emphasis-color-rgb), 0.65); + --bs-navbar-hover-color: rgba(var(--bs-emphasis-color-rgb), 0.8); + --bs-navbar-disabled-color: rgba(var(--bs-emphasis-color-rgb), 0.3); + --bs-navbar-active-color: rgba(var(--bs-emphasis-color-rgb), 1); + --bs-navbar-brand-padding-y: 0.3125rem; + --bs-navbar-brand-margin-end: 1rem; + --bs-navbar-brand-font-size: 1.25rem; + --bs-navbar-brand-color: rgba(var(--bs-emphasis-color-rgb), 1); + --bs-navbar-brand-hover-color: rgba(var(--bs-emphasis-color-rgb), 1); + --bs-navbar-nav-link-padding-x: 0.5rem; + --bs-navbar-toggler-padding-y: 0.25rem; + --bs-navbar-toggler-padding-x: 0.75rem; + --bs-navbar-toggler-font-size: 1.25rem; + --bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); + --bs-navbar-toggler-border-color: rgba(var(--bs-emphasis-color-rgb), 0.15); + --bs-navbar-toggler-border-radius: var(--bs-border-radius); + --bs-navbar-toggler-focus-width: 0.25rem; + --bs-navbar-toggler-transition: box-shadow 0.15s ease-in-out; + position: relative; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + padding: var(--bs-navbar-padding-y) var(--bs-navbar-padding-x); +} +.navbar > .container, +.navbar > .container-fluid, +.navbar > .container-sm, +.navbar > .container-md, +.navbar > .container-lg, +.navbar > .container-xl, +.navbar > .container-xxl { + display: flex; + flex-wrap: inherit; + 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); + margin-right: var(--bs-navbar-brand-margin-end); + font-size: var(--bs-navbar-brand-font-size); + color: var(--bs-navbar-brand-color); + white-space: nowrap; +} +.navbar-brand:hover, +.navbar-brand:focus { + color: var(--bs-navbar-brand-hover-color); +} + +.navbar-nav { + --bs-nav-link-padding-x: 0; + --bs-nav-link-padding-y: 0.5rem; + --bs-nav-link-font-weight: ; + --bs-nav-link-color: var(--bs-navbar-color); + --bs-nav-link-hover-color: var(--bs-navbar-hover-color); + --bs-nav-link-disabled-color: var(--bs-navbar-disabled-color); + display: flex; + flex-direction: column; + padding-left: 0; + 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; +} + +.navbar-text { + padding-top: 0.5rem; + padding-bottom: 0.5rem; + color: var(--bs-navbar-color); +} +.navbar-text a, +.navbar-text a:hover, +.navbar-text a:focus { + color: var(--bs-navbar-active-color); +} + +.navbar-collapse { + flex-basis: 100%; + flex-grow: 1; + align-items: center; +} + +.navbar-toggler { + padding: var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x); + font-size: var(--bs-navbar-toggler-font-size); + line-height: 1; + color: var(--bs-navbar-color); + background-color: transparent; + border: var(--bs-border-width) solid var(--bs-navbar-toggler-border-color); + 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; + box-shadow: 0 0 0 var(--bs-navbar-toggler-focus-width); +} + +.navbar-toggler-icon { + display: inline-block; + width: 1.5em; + height: 1.5em; + vertical-align: middle; + background-image: var(--bs-navbar-toggler-icon-bg); + background-repeat: no-repeat; + background-position: center; + background-size: 100%; +} + +.navbar-nav-scroll { + max-height: var(--bs-scroll-height, 75vh); + overflow-y: auto; +} + +@media (min-width: 576px) { + .navbar-expand-sm { + 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; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; + } + .navbar-expand-sm .offcanvas .offcanvas-header { + display: none; + } + .navbar-expand-sm .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + 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; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; + } + .navbar-expand-md .offcanvas .offcanvas-header { + display: none; + } + .navbar-expand-md .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + 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; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; + } + .navbar-expand-lg .offcanvas .offcanvas-header { + display: none; + } + .navbar-expand-lg .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + 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; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; + } + .navbar-expand-xl .offcanvas .offcanvas-header { + display: none; + } + .navbar-expand-xl .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + 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; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; + } + .navbar-expand-xxl .offcanvas .offcanvas-header { + display: none; + } + .navbar-expand-xxl .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + 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; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; +} +.navbar-expand .offcanvas .offcanvas-header { + display: none; +} +.navbar-expand .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; +} + +.navbar-dark, +.navbar[data-bs-theme='dark'] { + --bs-navbar-color: rgba(255, 255, 255, 0.55); + --bs-navbar-hover-color: rgba(255, 255, 255, 0.75); + --bs-navbar-disabled-color: rgba(255, 255, 255, 0.25); + --bs-navbar-active-color: #fff; + --bs-navbar-brand-color: #fff; + --bs-navbar-brand-hover-color: #fff; + --bs-navbar-toggler-border-color: rgba(255, 255, 255, 0.1); + --bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); +} + +[data-bs-theme='dark'] .navbar-toggler-icon { + --bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); +} + +.card { + --bs-card-spacer-y: 1rem; + --bs-card-spacer-x: 1rem; + --bs-card-title-spacer-y: 0.5rem; + --bs-card-title-color: ; + --bs-card-subtitle-color: ; + --bs-card-border-width: var(--bs-border-width); + --bs-card-border-color: var(--bs-border-color-translucent); + --bs-card-border-radius: var(--bs-border-radius); + --bs-card-box-shadow: ; + --bs-card-inner-border-radius: calc( + var(--bs-border-radius) - (var(--bs-border-width)) + ); + --bs-card-cap-padding-y: 0.5rem; + --bs-card-cap-padding-x: 1rem; + --bs-card-cap-bg: rgba(var(--bs-body-color-rgb), 0.03); + --bs-card-cap-color: ; + --bs-card-height: ; + --bs-card-color: ; + --bs-card-bg: var(--bs-body-bg); + --bs-card-img-overlay-padding: 1rem; + --bs-card-group-margin: 0.75rem; + position: relative; + display: flex; + flex-direction: column; + min-width: 0; + height: var(--bs-card-height); + color: var(--bs-body-color); + word-wrap: break-word; + background-color: var(--bs-card-bg); + background-clip: border-box; + 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; +} + +.card-body { + flex: 1 1 auto; + padding: var(--bs-card-spacer-y) var(--bs-card-spacer-x); + color: var(--bs-card-color); +} + +.card-title { + margin-bottom: var(--bs-card-title-spacer-y); + color: var(--bs-card-title-color); +} + +.card-subtitle { + margin-top: calc(-0.5 * var(--bs-card-title-spacer-y)); + margin-bottom: 0; + color: var(--bs-card-subtitle-color); +} + +.card-text:last-child { + margin-bottom: 0; +} + +.card-link + .card-link { + margin-left: var(--bs-card-spacer-x); +} + +.card-header { + padding: var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x); + margin-bottom: 0; + color: var(--bs-card-cap-color); + 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; +} + +.card-footer { + padding: var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x); + color: var(--bs-card-cap-color); + 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); +} + +.card-header-tabs { + margin-right: calc(-0.5 * var(--bs-card-cap-padding-x)); + margin-bottom: calc(-1 * var(--bs-card-cap-padding-y)); + 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); +} + +.card-header-pills { + margin-right: calc(-0.5 * var(--bs-card-cap-padding-x)); + margin-left: calc(-0.5 * var(--bs-card-cap-padding-x)); +} + +.card-img-overlay { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + padding: var(--bs-card-img-overlay-padding); + border-radius: var(--bs-card-inner-border-radius); +} + +.card-img, +.card-img-top, +.card-img-bottom { + width: 100%; +} + +.card-img, +.card-img-top { + border-top-left-radius: var(--bs-card-inner-border-radius); + border-top-right-radius: var(--bs-card-inner-border-radius); +} + +.card-img, +.card-img-bottom { + border-bottom-right-radius: var(--bs-card-inner-border-radius); + border-bottom-left-radius: var(--bs-card-inner-border-radius); +} + +.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; + } +} + +.accordion { + --bs-accordion-color: var(--bs-body-color); + --bs-accordion-bg: var(--bs-body-bg); + --bs-accordion-transition: color 0.15s ease-in-out, + background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, + box-shadow 0.15s ease-in-out, border-radius 0.15s ease; + --bs-accordion-border-color: var(--bs-border-color); + --bs-accordion-border-width: var(--bs-border-width); + --bs-accordion-border-radius: var(--bs-border-radius); + --bs-accordion-inner-border-radius: calc( + var(--bs-border-radius) - (var(--bs-border-width)) + ); + --bs-accordion-btn-padding-x: 1.25rem; + --bs-accordion-btn-padding-y: 1rem; + --bs-accordion-btn-color: var(--bs-body-color); + --bs-accordion-btn-bg: var(--bs-accordion-bg); + --bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); + --bs-accordion-btn-icon-width: 1.25rem; + --bs-accordion-btn-icon-transform: rotate(-180deg); + --bs-accordion-btn-icon-transition: transform 0.2s ease-in-out; + --bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23144b2b'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); + --bs-accordion-btn-focus-border-color: #98ddb5; + --bs-accordion-btn-focus-box-shadow: 0 0 0 0.25rem rgba(49, 187, 107, 0.25); + --bs-accordion-body-padding-x: 1.25rem; + --bs-accordion-body-padding-y: 1rem; + --bs-accordion-active-color: var(--bs-primary-text-emphasis); + --bs-accordion-active-bg: var(--bs-primary-bg-subtle); +} + +.accordion-button { + position: relative; + display: flex; + align-items: center; + width: 100%; + padding: var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x); + font-size: 1rem; + color: var(--bs-accordion-btn-color); + text-align: left; + background-color: var(--bs-accordion-btn-bg); + border: 0; + border-radius: 0; + 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); + height: var(--bs-accordion-btn-icon-width); + margin-left: auto; + content: ''; + background-image: var(--bs-accordion-btn-icon); + background-repeat: no-repeat; + 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); + outline: 0; + box-shadow: var(--bs-accordion-btn-focus-box-shadow); +} + +.accordion-header { + margin-bottom: 0; +} + +.accordion-item { + color: var(--bs-accordion-color); + background-color: var(--bs-accordion-bg); + 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); +} + +.accordion-body { + padding: var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x); +} + +.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; +} + +[data-bs-theme='dark'] .accordion-button::after { + --bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%2383d6a6'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); + --bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%2383d6a6'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); +} + +.breadcrumb { + --bs-breadcrumb-padding-x: 0; + --bs-breadcrumb-padding-y: 0; + --bs-breadcrumb-margin-bottom: 1rem; + --bs-breadcrumb-bg: ; + --bs-breadcrumb-border-radius: ; + --bs-breadcrumb-divider-color: var(--bs-secondary-color); + --bs-breadcrumb-item-padding-x: 0.5rem; + --bs-breadcrumb-item-active-color: var(--bs-secondary-color); + display: flex; + flex-wrap: wrap; + padding: var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x); + margin-bottom: var(--bs-breadcrumb-margin-bottom); + font-size: var(--bs-breadcrumb-font-size); + list-style: none; + background-color: var(--bs-breadcrumb-bg); + border-radius: var(--bs-breadcrumb-border-radius); +} + +.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); + color: var(--bs-breadcrumb-divider-color); + content: var(--bs-breadcrumb-divider, '/') + /* rtl: var(--bs-breadcrumb-divider, "/") */; +} +.breadcrumb-item.active { + color: var(--bs-breadcrumb-item-active-color); +} + +.pagination { + --bs-pagination-padding-x: 0.75rem; + --bs-pagination-padding-y: 0.375rem; + --bs-pagination-font-size: 1rem; + --bs-pagination-color: var(--bs-link-color); + --bs-pagination-bg: var(--bs-body-bg); + --bs-pagination-border-width: var(--bs-border-width); + --bs-pagination-border-color: var(--bs-border-color); + --bs-pagination-border-radius: var(--bs-border-radius); + --bs-pagination-hover-color: var(--bs-link-hover-color); + --bs-pagination-hover-bg: var(--bs-tertiary-bg); + --bs-pagination-hover-border-color: var(--bs-border-color); + --bs-pagination-focus-color: var(--bs-link-hover-color); + --bs-pagination-focus-bg: var(--bs-secondary-bg); + --bs-pagination-focus-box-shadow: 0 0 0 0.25rem rgba(49, 187, 107, 0.25); + --bs-pagination-active-color: #fff; + --bs-pagination-active-bg: #31bb6b; + --bs-pagination-active-border-color: #31bb6b; + --bs-pagination-disabled-color: var(--bs-secondary-color); + --bs-pagination-disabled-bg: var(--bs-secondary-bg); + --bs-pagination-disabled-border-color: var(--bs-border-color); + display: flex; + padding-left: 0; + list-style: none; +} + +.page-link { + position: relative; + display: block; + padding: var(--bs-pagination-padding-y) var(--bs-pagination-padding-x); + font-size: var(--bs-pagination-font-size); + color: var(--bs-pagination-color); + background-color: var(--bs-pagination-bg); + border: var(--bs-pagination-border-width) solid + var(--bs-pagination-border-color); + transition: + color 0.15s ease-in-out, + background-color 0.15s ease-in-out, + 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); + background-color: var(--bs-pagination-focus-bg); + outline: 0; + box-shadow: var(--bs-pagination-focus-box-shadow); +} +.page-link.active, +.active > .page-link { + z-index: 3; + color: var(--bs-pagination-active-color); + 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); + pointer-events: none; + background-color: var(--bs-pagination-disabled-bg); + border-color: var(--bs-pagination-disabled-border-color); +} + +.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); +} + +.pagination-lg { + --bs-pagination-padding-x: 1.5rem; + --bs-pagination-padding-y: 0.75rem; + --bs-pagination-font-size: 1.25rem; + --bs-pagination-border-radius: var(--bs-border-radius-lg); +} + +.pagination-sm { + --bs-pagination-padding-x: 0.5rem; + --bs-pagination-padding-y: 0.25rem; + --bs-pagination-font-size: 0.875rem; + --bs-pagination-border-radius: var(--bs-border-radius-sm); +} + +.badge { + --bs-badge-padding-x: 0.65em; + --bs-badge-padding-y: 0.35em; + --bs-badge-font-size: 0.75em; + --bs-badge-font-weight: 700; + --bs-badge-color: #fff; + --bs-badge-border-radius: var(--bs-border-radius); + display: inline-block; + padding: var(--bs-badge-padding-y) var(--bs-badge-padding-x); + font-size: var(--bs-badge-font-size); + font-weight: var(--bs-badge-font-weight); + line-height: 1; + color: var(--bs-badge-color); + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: var(--bs-badge-border-radius); +} +.badge:empty { + display: none; +} + +.btn .badge { + position: relative; + top: -1px; +} + +.alert { + --bs-alert-bg: transparent; + --bs-alert-padding-x: 1rem; + --bs-alert-padding-y: 1rem; + --bs-alert-margin-bottom: 1rem; + --bs-alert-color: inherit; + --bs-alert-border-color: transparent; + --bs-alert-border: var(--bs-border-width) solid var(--bs-alert-border-color); + --bs-alert-border-radius: var(--bs-border-radius); + --bs-alert-link-color: inherit; + position: relative; + padding: var(--bs-alert-padding-y) var(--bs-alert-padding-x); + margin-bottom: var(--bs-alert-margin-bottom); + color: var(--bs-alert-color); + background-color: var(--bs-alert-bg); + border: var(--bs-alert-border); + border-radius: var(--bs-alert-border-radius); +} + +.alert-heading { + color: inherit; +} + +.alert-link { + font-weight: 700; + color: var(--bs-alert-link-color); +} + +.alert-dismissible { + padding-right: 3rem; +} +.alert-dismissible .btn-close { + position: absolute; + top: 0; + right: 0; + z-index: 2; + padding: 1.25rem 1rem; +} + +.alert-primary { + --bs-alert-color: var(--bs-primary-text-emphasis); + --bs-alert-bg: var(--bs-primary-bg-subtle); + --bs-alert-border-color: var(--bs-primary-border-subtle); + --bs-alert-link-color: var(--bs-primary-text-emphasis); +} + +.alert-secondary { + --bs-alert-color: var(--bs-secondary-text-emphasis); + --bs-alert-bg: var(--bs-secondary-bg-subtle); + --bs-alert-border-color: var(--bs-secondary-border-subtle); + --bs-alert-link-color: var(--bs-secondary-text-emphasis); +} + +.alert-success { + --bs-alert-color: var(--bs-success-text-emphasis); + --bs-alert-bg: var(--bs-success-bg-subtle); + --bs-alert-border-color: var(--bs-success-border-subtle); + --bs-alert-link-color: var(--bs-success-text-emphasis); +} + +.alert-info { + --bs-alert-color: var(--bs-info-text-emphasis); + --bs-alert-bg: var(--bs-info-bg-subtle); + --bs-alert-border-color: var(--bs-info-border-subtle); + --bs-alert-link-color: var(--bs-info-text-emphasis); +} + +.alert-warning { + --bs-alert-color: var(--bs-warning-text-emphasis); + --bs-alert-bg: var(--bs-warning-bg-subtle); + --bs-alert-border-color: var(--bs-warning-border-subtle); + --bs-alert-link-color: var(--bs-warning-text-emphasis); +} + +.alert-danger { + --bs-alert-color: var(--bs-danger-text-emphasis); + --bs-alert-bg: var(--bs-danger-bg-subtle); + --bs-alert-border-color: var(--bs-danger-border-subtle); + --bs-alert-link-color: var(--bs-danger-text-emphasis); +} + +.alert-light { + --bs-alert-color: var(--bs-light-text-emphasis); + --bs-alert-bg: var(--bs-light-bg-subtle); + --bs-alert-border-color: var(--bs-light-border-subtle); + --bs-alert-link-color: var(--bs-light-text-emphasis); +} + +.alert-dark { + --bs-alert-color: var(--bs-dark-text-emphasis); + --bs-alert-bg: var(--bs-dark-bg-subtle); + --bs-alert-border-color: var(--bs-dark-border-subtle); + --bs-alert-link-color: var(--bs-dark-text-emphasis); +} + +@keyframes progress-bar-stripes { + 0% { + background-position-x: 1rem; + } +} +.progress, +.progress-stacked { + --bs-progress-height: 1rem; + --bs-progress-font-size: 0.75rem; + --bs-progress-bg: var(--bs-secondary-bg); + --bs-progress-border-radius: var(--bs-border-radius); + --bs-progress-box-shadow: var(--bs-box-shadow-inset); + --bs-progress-bar-color: #fff; + --bs-progress-bar-bg: #31bb6b; + --bs-progress-bar-transition: width 0.6s ease; + display: flex; + height: var(--bs-progress-height); + overflow: hidden; + font-size: var(--bs-progress-font-size); + background-color: var(--bs-progress-bg); + border-radius: var(--bs-progress-border-radius); +} + +.progress-bar { + display: flex; + flex-direction: column; + justify-content: center; + overflow: hidden; + color: var(--bs-progress-bar-color); + text-align: center; + white-space: nowrap; + background-color: var(--bs-progress-bar-bg); + transition: var(--bs-progress-bar-transition); +} +@media (prefers-reduced-motion: reduce) { + .progress-bar { + transition: none; + } +} + +.progress-bar-striped { + background-image: linear-gradient( + 45deg, + rgba(255, 255, 255, 0.15) 25%, + transparent 25%, + transparent 50%, + rgba(255, 255, 255, 0.15) 50%, + rgba(255, 255, 255, 0.15) 75%, + transparent 75%, + transparent + ); + background-size: var(--bs-progress-height) var(--bs-progress-height); +} + +.progress-stacked > .progress { + overflow: visible; +} + +.progress-stacked > .progress > .progress-bar { + width: 100%; +} + +.progress-bar-animated { + animation: 1s linear infinite progress-bar-stripes; +} +@media (prefers-reduced-motion: reduce) { + .progress-bar-animated { + animation: none; + } +} + +.list-group { + --bs-list-group-color: var(--bs-body-color); + --bs-list-group-bg: var(--bs-body-bg); + --bs-list-group-border-color: var(--bs-border-color); + --bs-list-group-border-width: var(--bs-border-width); + --bs-list-group-border-radius: var(--bs-border-radius); + --bs-list-group-item-padding-x: 1rem; + --bs-list-group-item-padding-y: 0.5rem; + --bs-list-group-action-color: var(--bs-secondary-color); + --bs-list-group-action-hover-color: var(--bs-emphasis-color); + --bs-list-group-action-hover-bg: var(--bs-tertiary-bg); + --bs-list-group-action-active-color: var(--bs-body-color); + --bs-list-group-action-active-bg: var(--bs-secondary-bg); + --bs-list-group-disabled-color: var(--bs-secondary-color); + --bs-list-group-disabled-bg: var(--bs-body-bg); + --bs-list-group-active-color: #fff; + --bs-list-group-active-bg: #31bb6b; + --bs-list-group-active-border-color: #31bb6b; + display: flex; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; + border-radius: var(--bs-list-group-border-radius); +} + +.list-group-numbered { + list-style-type: none; + counter-reset: section; +} +.list-group-numbered > .list-group-item::before { + content: counters(section, '.') '. '; + counter-increment: section; +} + +.list-group-item-action { + width: 100%; + color: var(--bs-list-group-action-color); + text-align: inherit; +} +.list-group-item-action:hover, +.list-group-item-action:focus { + z-index: 1; + color: var(--bs-list-group-action-hover-color); + 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); +} + +.list-group-item { + position: relative; + display: block; + padding: var(--bs-list-group-item-padding-y) + var(--bs-list-group-item-padding-x); + color: var(--bs-list-group-color); + background-color: var(--bs-list-group-bg); + 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); +} + +.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); +} + +@media (min-width: 576px) { + .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; +} + +.list-group-item-primary { + --bs-list-group-color: var(--bs-primary-text-emphasis); + --bs-list-group-bg: var(--bs-primary-bg-subtle); + --bs-list-group-border-color: var(--bs-primary-border-subtle); + --bs-list-group-action-hover-color: var(--bs-emphasis-color); + --bs-list-group-action-hover-bg: var(--bs-primary-border-subtle); + --bs-list-group-action-active-color: var(--bs-emphasis-color); + --bs-list-group-action-active-bg: var(--bs-primary-border-subtle); + --bs-list-group-active-color: var(--bs-primary-bg-subtle); + --bs-list-group-active-bg: var(--bs-primary-text-emphasis); + --bs-list-group-active-border-color: var(--bs-primary-text-emphasis); +} + +.list-group-item-secondary { + --bs-list-group-color: var(--bs-secondary-text-emphasis); + --bs-list-group-bg: var(--bs-secondary-bg-subtle); + --bs-list-group-border-color: var(--bs-secondary-border-subtle); + --bs-list-group-action-hover-color: var(--bs-emphasis-color); + --bs-list-group-action-hover-bg: var(--bs-secondary-border-subtle); + --bs-list-group-action-active-color: var(--bs-emphasis-color); + --bs-list-group-action-active-bg: var(--bs-secondary-border-subtle); + --bs-list-group-active-color: var(--bs-secondary-bg-subtle); + --bs-list-group-active-bg: var(--bs-secondary-text-emphasis); + --bs-list-group-active-border-color: var(--bs-secondary-text-emphasis); +} + +.list-group-item-success { + --bs-list-group-color: var(--bs-success-text-emphasis); + --bs-list-group-bg: var(--bs-success-bg-subtle); + --bs-list-group-border-color: var(--bs-success-border-subtle); + --bs-list-group-action-hover-color: var(--bs-emphasis-color); + --bs-list-group-action-hover-bg: var(--bs-success-border-subtle); + --bs-list-group-action-active-color: var(--bs-emphasis-color); + --bs-list-group-action-active-bg: var(--bs-success-border-subtle); + --bs-list-group-active-color: var(--bs-success-bg-subtle); + --bs-list-group-active-bg: var(--bs-success-text-emphasis); + --bs-list-group-active-border-color: var(--bs-success-text-emphasis); +} + +.list-group-item-info { + --bs-list-group-color: var(--bs-info-text-emphasis); + --bs-list-group-bg: var(--bs-info-bg-subtle); + --bs-list-group-border-color: var(--bs-info-border-subtle); + --bs-list-group-action-hover-color: var(--bs-emphasis-color); + --bs-list-group-action-hover-bg: var(--bs-info-border-subtle); + --bs-list-group-action-active-color: var(--bs-emphasis-color); + --bs-list-group-action-active-bg: var(--bs-info-border-subtle); + --bs-list-group-active-color: var(--bs-info-bg-subtle); + --bs-list-group-active-bg: var(--bs-info-text-emphasis); + --bs-list-group-active-border-color: var(--bs-info-text-emphasis); +} + +.list-group-item-warning { + --bs-list-group-color: var(--bs-warning-text-emphasis); + --bs-list-group-bg: var(--bs-warning-bg-subtle); + --bs-list-group-border-color: var(--bs-warning-border-subtle); + --bs-list-group-action-hover-color: var(--bs-emphasis-color); + --bs-list-group-action-hover-bg: var(--bs-warning-border-subtle); + --bs-list-group-action-active-color: var(--bs-emphasis-color); + --bs-list-group-action-active-bg: var(--bs-warning-border-subtle); + --bs-list-group-active-color: var(--bs-warning-bg-subtle); + --bs-list-group-active-bg: var(--bs-warning-text-emphasis); + --bs-list-group-active-border-color: var(--bs-warning-text-emphasis); +} + +.list-group-item-danger { + --bs-list-group-color: var(--bs-danger-text-emphasis); + --bs-list-group-bg: var(--bs-danger-bg-subtle); + --bs-list-group-border-color: var(--bs-danger-border-subtle); + --bs-list-group-action-hover-color: var(--bs-emphasis-color); + --bs-list-group-action-hover-bg: var(--bs-danger-border-subtle); + --bs-list-group-action-active-color: var(--bs-emphasis-color); + --bs-list-group-action-active-bg: var(--bs-danger-border-subtle); + --bs-list-group-active-color: var(--bs-danger-bg-subtle); + --bs-list-group-active-bg: var(--bs-danger-text-emphasis); + --bs-list-group-active-border-color: var(--bs-danger-text-emphasis); +} + +.list-group-item-light { + --bs-list-group-color: var(--bs-light-text-emphasis); + --bs-list-group-bg: var(--bs-light-bg-subtle); + --bs-list-group-border-color: var(--bs-light-border-subtle); + --bs-list-group-action-hover-color: var(--bs-emphasis-color); + --bs-list-group-action-hover-bg: var(--bs-light-border-subtle); + --bs-list-group-action-active-color: var(--bs-emphasis-color); + --bs-list-group-action-active-bg: var(--bs-light-border-subtle); + --bs-list-group-active-color: var(--bs-light-bg-subtle); + --bs-list-group-active-bg: var(--bs-light-text-emphasis); + --bs-list-group-active-border-color: var(--bs-light-text-emphasis); +} + +.list-group-item-dark { + --bs-list-group-color: var(--bs-dark-text-emphasis); + --bs-list-group-bg: var(--bs-dark-bg-subtle); + --bs-list-group-border-color: var(--bs-dark-border-subtle); + --bs-list-group-action-hover-color: var(--bs-emphasis-color); + --bs-list-group-action-hover-bg: var(--bs-dark-border-subtle); + --bs-list-group-action-active-color: var(--bs-emphasis-color); + --bs-list-group-action-active-bg: var(--bs-dark-border-subtle); + --bs-list-group-active-color: var(--bs-dark-bg-subtle); + --bs-list-group-active-bg: var(--bs-dark-text-emphasis); + --bs-list-group-active-border-color: var(--bs-dark-text-emphasis); +} + +.btn-close { + --bs-btn-close-color: #000; + --bs-btn-close-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e"); + --bs-btn-close-opacity: 0.5; + --bs-btn-close-hover-opacity: 0.75; + --bs-btn-close-focus-shadow: 0 0 0 0.25rem rgba(49, 187, 107, 0.25); + --bs-btn-close-focus-opacity: 1; + --bs-btn-close-disabled-opacity: 0.25; + --bs-btn-close-white-filter: invert(1) grayscale(100%) brightness(200%); + box-sizing: content-box; + width: 1em; + height: 1em; + padding: 0.25em 0.25em; + color: var(--bs-btn-close-color); + background: transparent var(--bs-btn-close-bg) center/1em auto no-repeat; + border: 0; + 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; + user-select: none; + opacity: var(--bs-btn-close-disabled-opacity); +} + +.btn-close-white { + filter: var(--bs-btn-close-white-filter); +} + +[data-bs-theme='dark'] .btn-close { + filter: var(--bs-btn-close-white-filter); +} + +.toast { + --bs-toast-zindex: 1090; + --bs-toast-padding-x: 0.75rem; + --bs-toast-padding-y: 0.5rem; + --bs-toast-spacing: 1.5rem; + --bs-toast-max-width: 350px; + --bs-toast-font-size: 0.875rem; + --bs-toast-color: ; + --bs-toast-bg: rgba(var(--bs-body-bg-rgb), 0.85); + --bs-toast-border-width: var(--bs-border-width); + --bs-toast-border-color: var(--bs-border-color-translucent); + --bs-toast-border-radius: var(--bs-border-radius); + --bs-toast-box-shadow: var(--bs-box-shadow); + --bs-toast-header-color: var(--bs-secondary-color); + --bs-toast-header-bg: rgba(var(--bs-body-bg-rgb), 0.85); + --bs-toast-header-border-color: var(--bs-border-color-translucent); + width: var(--bs-toast-max-width); + max-width: 100%; + font-size: var(--bs-toast-font-size); + color: var(--bs-toast-color); + pointer-events: auto; + background-color: var(--bs-toast-bg); + background-clip: padding-box; + border: var(--bs-toast-border-width) solid var(--bs-toast-border-color); + box-shadow: var(--bs-toast-box-shadow); + border-radius: var(--bs-toast-border-radius); +} +.toast.showing { + opacity: 0; +} +.toast:not(.show) { + display: none; +} + +.toast-container { + --bs-toast-zindex: 1090; + position: absolute; + z-index: var(--bs-toast-zindex); + width: max-content; + max-width: 100%; + pointer-events: none; +} +.toast-container > :not(:last-child) { + margin-bottom: var(--bs-toast-spacing); +} + +.toast-header { + display: flex; + align-items: center; + padding: var(--bs-toast-padding-y) var(--bs-toast-padding-x); + color: var(--bs-toast-header-color); + background-color: var(--bs-toast-header-bg); + background-clip: padding-box; + border-bottom: var(--bs-toast-border-width) solid + var(--bs-toast-header-border-color); + border-top-left-radius: calc( + var(--bs-toast-border-radius) - var(--bs-toast-border-width) + ); + border-top-right-radius: calc( + 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); +} + +.toast-body { + padding: var(--bs-toast-padding-x); + word-wrap: break-word; +} + +.modal { + --bs-modal-zindex: 1055; + --bs-modal-width: 500px; + --bs-modal-padding: 1rem; + --bs-modal-margin: 0.5rem; + --bs-modal-color: ; + --bs-modal-bg: var(--bs-body-bg); + --bs-modal-border-color: var(--bs-border-color-translucent); + --bs-modal-border-width: var(--bs-border-width); + --bs-modal-border-radius: var(--bs-border-radius-lg); + --bs-modal-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); + --bs-modal-inner-border-radius: calc( + var(--bs-border-radius-lg) - (var(--bs-border-width)) + ); + --bs-modal-header-padding-x: 1rem; + --bs-modal-header-padding-y: 1rem; + --bs-modal-header-padding: 1rem 1rem; + --bs-modal-header-border-color: var(--bs-border-color); + --bs-modal-header-border-width: var(--bs-border-width); + --bs-modal-title-line-height: 1.5; + --bs-modal-footer-gap: 0.5rem; + --bs-modal-footer-bg: ; + --bs-modal-footer-border-color: var(--bs-border-color); + --bs-modal-footer-border-width: var(--bs-border-width); + position: fixed; + top: 0; + left: 0; + z-index: var(--bs-modal-zindex); + display: none; + width: 100%; + height: 100%; + overflow-x: hidden; + overflow-y: auto; + outline: 0; +} + +.modal-dialog { + position: relative; + width: auto; + 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); +} + +.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; +} + +.modal-dialog-centered { + display: flex; + align-items: center; + min-height: calc(100% - var(--bs-modal-margin) * 2); +} + +.modal-content { + position: relative; + display: flex; + flex-direction: column; + width: 100%; + color: var(--bs-modal-color); + pointer-events: auto; + background-color: var(--bs-modal-bg); + background-clip: padding-box; + border: var(--bs-modal-border-width) solid var(--bs-modal-border-color); + border-radius: var(--bs-modal-border-radius); + outline: 0; +} + +.modal-backdrop { + --bs-backdrop-zindex: 1050; + --bs-backdrop-bg: #000; + --bs-backdrop-opacity: 0.5; + position: fixed; + top: 0; + left: 0; + z-index: var(--bs-backdrop-zindex); + width: 100vw; + height: 100vh; + background-color: var(--bs-backdrop-bg); +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop.show { + opacity: var(--bs-backdrop-opacity); +} + +.modal-header { + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: space-between; + padding: var(--bs-modal-header-padding); + border-bottom: var(--bs-modal-header-border-width) solid + var(--bs-modal-header-border-color); + 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); + margin: calc(-0.5 * var(--bs-modal-header-padding-y)) + calc(-0.5 * var(--bs-modal-header-padding-x)) + calc(-0.5 * var(--bs-modal-header-padding-y)) auto; +} + +.modal-title { + margin-bottom: 0; + line-height: var(--bs-modal-title-line-height); +} + +.modal-body { + position: relative; + flex: 1 1 auto; + padding: var(--bs-modal-padding); +} + +.modal-footer { + display: flex; + flex-shrink: 0; + flex-wrap: wrap; + align-items: center; + justify-content: flex-end; + padding: calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * 0.5); + background-color: var(--bs-modal-footer-bg); + border-top: var(--bs-modal-footer-border-width) solid + var(--bs-modal-footer-border-color); + 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); +} + +@media (min-width: 576px) { + .modal { + --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; +} + +@media (max-width: 575.98px) { + .modal-fullscreen-sm-down { + width: 100vw; + max-width: none; + 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; + max-width: none; + 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; + max-width: none; + 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; + max-width: none; + 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; + max-width: none; + 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; + --bs-tooltip-padding-x: 0.5rem; + --bs-tooltip-padding-y: 0.25rem; + --bs-tooltip-margin: ; + --bs-tooltip-font-size: 0.875rem; + --bs-tooltip-color: var(--bs-body-bg); + --bs-tooltip-bg: var(--bs-emphasis-color); + --bs-tooltip-border-radius: var(--bs-border-radius); + --bs-tooltip-opacity: 0.9; + --bs-tooltip-arrow-width: 0.8rem; + --bs-tooltip-arrow-height: 0.4rem; + z-index: var(--bs-tooltip-zindex); + display: block; + margin: var(--bs-tooltip-margin); + font-family: var(--bs-font-sans-serif); + font-style: normal; + font-weight: 400; + line-height: 1.5; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + white-space: normal; + word-spacing: normal; + line-break: auto; + font-size: var(--bs-tooltip-font-size); + 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: ''; + border-color: transparent; + border-style: solid; +} + +.bs-tooltip-top .tooltip-arrow, +.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; + border-width: var(--bs-tooltip-arrow-height) + calc(var(--bs-tooltip-arrow-width) * 0.5) 0; + border-top-color: var(--bs-tooltip-bg); +} + +/* rtl:begin:ignore */ +.bs-tooltip-end .tooltip-arrow, +.bs-tooltip-auto[data-popper-placement^='right'] .tooltip-arrow { + left: calc(-1 * var(--bs-tooltip-arrow-height)); + 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; + border-width: calc(var(--bs-tooltip-arrow-width) * 0.5) + var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * 0.5) 0; + border-right-color: var(--bs-tooltip-bg); +} + +/* rtl:end:ignore */ +.bs-tooltip-bottom .tooltip-arrow, +.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; + border-width: 0 calc(var(--bs-tooltip-arrow-width) * 0.5) + var(--bs-tooltip-arrow-height); + border-bottom-color: var(--bs-tooltip-bg); +} + +/* rtl:begin:ignore */ +.bs-tooltip-start .tooltip-arrow, +.bs-tooltip-auto[data-popper-placement^='left'] .tooltip-arrow { + right: calc(-1 * var(--bs-tooltip-arrow-height)); + 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; + border-width: calc(var(--bs-tooltip-arrow-width) * 0.5) 0 + calc(var(--bs-tooltip-arrow-width) * 0.5) var(--bs-tooltip-arrow-height); + border-left-color: var(--bs-tooltip-bg); +} + +/* rtl:end:ignore */ +.tooltip-inner { + max-width: var(--bs-tooltip-max-width); + padding: var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x); + color: var(--bs-tooltip-color); + text-align: center; + background-color: var(--bs-tooltip-bg); + border-radius: var(--bs-tooltip-border-radius); +} + +.popover { + --bs-popover-zindex: 1070; + --bs-popover-max-width: 276px; + --bs-popover-font-size: 0.875rem; + --bs-popover-bg: var(--bs-body-bg); + --bs-popover-border-width: var(--bs-border-width); + --bs-popover-border-color: var(--bs-border-color-translucent); + --bs-popover-border-radius: var(--bs-border-radius-lg); + --bs-popover-inner-border-radius: calc( + var(--bs-border-radius-lg) - var(--bs-border-width) + ); + --bs-popover-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); + --bs-popover-header-padding-x: 1rem; + --bs-popover-header-padding-y: 0.5rem; + --bs-popover-header-font-size: 1rem; + --bs-popover-header-color: inherit; + --bs-popover-header-bg: var(--bs-secondary-bg); + --bs-popover-body-padding-x: 1rem; + --bs-popover-body-padding-y: 1rem; + --bs-popover-body-color: var(--bs-body-color); + --bs-popover-arrow-width: 1rem; + --bs-popover-arrow-height: 0.5rem; + --bs-popover-arrow-border: var(--bs-popover-border-color); + z-index: var(--bs-popover-zindex); + display: block; + max-width: var(--bs-popover-max-width); + font-family: var(--bs-font-sans-serif); + font-style: normal; + font-weight: 400; + line-height: 1.5; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + white-space: normal; + word-spacing: normal; + line-break: auto; + font-size: var(--bs-popover-font-size); + word-wrap: break-word; + background-color: var(--bs-popover-bg); + background-clip: padding-box; + 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; + display: block; + content: ''; + border-color: transparent; + border-style: solid; + border-width: 0; +} + +.bs-popover-top > .popover-arrow, +.bs-popover-auto[data-popper-placement^='top'] > .popover-arrow { + bottom: calc( + -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, +.bs-popover-auto[data-popper-placement^='top'] > .popover-arrow::after { + 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); + border-top-color: var(--bs-popover-bg); +} + +/* rtl:begin:ignore */ +.bs-popover-end > .popover-arrow, +.bs-popover-auto[data-popper-placement^='right'] > .popover-arrow { + left: calc( + -1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width) + ); + 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, +.bs-popover-auto[data-popper-placement^='right'] > .popover-arrow::after { + 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); + border-right-color: var(--bs-popover-bg); +} + +/* rtl:end:ignore */ +.bs-popover-bottom > .popover-arrow, +.bs-popover-auto[data-popper-placement^='bottom'] > .popover-arrow { + top: calc( + -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, +.bs-popover-auto[data-popper-placement^='bottom'] > .popover-arrow::after { + 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; + top: 0; + left: 50%; + display: block; + width: var(--bs-popover-arrow-width); + margin-left: calc(-0.5 * var(--bs-popover-arrow-width)); + content: ''; + border-bottom: var(--bs-popover-border-width) solid + var(--bs-popover-header-bg); +} + +/* rtl:begin:ignore */ +.bs-popover-start > .popover-arrow, +.bs-popover-auto[data-popper-placement^='left'] > .popover-arrow { + right: calc( + -1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width) + ); + 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, +.bs-popover-auto[data-popper-placement^='left'] > .popover-arrow::after { + 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); + border-left-color: var(--bs-popover-bg); +} + +/* rtl:end:ignore */ +.popover-header { + padding: var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x); + margin-bottom: 0; + font-size: var(--bs-popover-header-font-size); + color: var(--bs-popover-header-color); + background-color: var(--bs-popover-header-bg); + border-bottom: var(--bs-popover-border-width) solid + var(--bs-popover-border-color); + 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; +} + +.popover-body { + padding: var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x); + color: var(--bs-popover-body-color); +} + +.carousel { + position: relative; +} + +.carousel.pointer-event { + touch-action: pan-y; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} +.carousel-inner::after { + display: block; + clear: both; + content: ''; +} + +.carousel-item { + position: relative; + display: none; + float: left; + width: 100%; + margin-right: -100%; + backface-visibility: hidden; + transition: transform 0.6s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .carousel-item { + transition: none; + } +} + +.carousel-item.active, +.carousel-item-next, +.carousel-item-prev { + display: block; +} + +.carousel-item-next:not(.carousel-item-start), +.active.carousel-item-end { + transform: translateX(100%); +} + +.carousel-item-prev:not(.carousel-item-end), +.active.carousel-item-start { + transform: translateX(-100%); +} + +.carousel-fade .carousel-item { + opacity: 0; + 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 { + transition: none; + } +} + +.carousel-control-prev, +.carousel-control-next { + position: absolute; + top: 0; + bottom: 0; + z-index: 1; + display: flex; + align-items: center; + justify-content: center; + width: 15%; + padding: 0; + color: #fff; + text-align: center; + background: none; + border: 0; + 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, +.carousel-control-next:focus { + color: #fff; + text-decoration: none; + outline: 0; + opacity: 0.9; +} + +.carousel-control-prev { + left: 0; +} + +.carousel-control-next { + right: 0; +} + +.carousel-control-prev-icon, +.carousel-control-next-icon { + display: inline-block; + width: 2rem; + height: 2rem; + background-repeat: no-repeat; + background-position: 50%; + background-size: 100% 100%; +} + +/* rtl:options: { + "autoRename": true, + "stringMap":[ { + "name" : "prev-next", + "search" : "prev", + "replace" : "next" + } ] + } */ +.carousel-control-prev-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e"); +} + +.carousel-control-next-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); +} + +.carousel-indicators { + position: absolute; + right: 0; + bottom: 0; + left: 0; + z-index: 2; + display: flex; + justify-content: center; + padding: 0; + margin-right: 15%; + margin-bottom: 1rem; + margin-left: 15%; +} +.carousel-indicators [data-bs-target] { + box-sizing: content-box; + flex: 0 1 auto; + width: 30px; + height: 3px; + padding: 0; + margin-right: 3px; + margin-left: 3px; + text-indent: -999px; + cursor: pointer; + background-color: #fff; + background-clip: padding-box; + border: 0; + border-top: 10px solid transparent; + border-bottom: 10px solid transparent; + 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; +} + +.carousel-caption { + position: absolute; + right: 15%; + bottom: 1.25rem; + left: 15%; + padding-top: 1.25rem; + padding-bottom: 1.25rem; + color: #fff; + text-align: center; +} + +.carousel-dark .carousel-control-prev-icon, +.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; +} + +[data-bs-theme='dark'] .carousel .carousel-control-prev-icon, +[data-bs-theme='dark'] .carousel .carousel-control-next-icon, +[data-bs-theme='dark'].carousel .carousel-control-prev-icon, +[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; +} + +.spinner-grow, +.spinner-border { + display: inline-block; + width: var(--bs-spinner-width); + height: var(--bs-spinner-height); + vertical-align: var(--bs-spinner-vertical-align); + border-radius: 50%; + animation: var(--bs-spinner-animation-speed) linear infinite + var(--bs-spinner-animation-name); +} + +@keyframes spinner-border { + to { + transform: rotate(360deg) /* rtl:ignore */; + } +} +.spinner-border { + --bs-spinner-width: 2rem; + --bs-spinner-height: 2rem; + --bs-spinner-vertical-align: -0.125em; + --bs-spinner-border-width: 0.25em; + --bs-spinner-animation-speed: 0.75s; + --bs-spinner-animation-name: spinner-border; + border: var(--bs-spinner-border-width) solid currentcolor; + border-right-color: transparent; +} + +.spinner-border-sm { + --bs-spinner-width: 1rem; + --bs-spinner-height: 1rem; + --bs-spinner-border-width: 0.2em; +} + +@keyframes spinner-grow { + 0% { + transform: scale(0); + } + 50% { + opacity: 1; + transform: none; + } +} +.spinner-grow { + --bs-spinner-width: 2rem; + --bs-spinner-height: 2rem; + --bs-spinner-vertical-align: -0.125em; + --bs-spinner-animation-speed: 0.75s; + --bs-spinner-animation-name: spinner-grow; + background-color: currentcolor; + opacity: 0; +} + +.spinner-grow-sm { + --bs-spinner-width: 1rem; + --bs-spinner-height: 1rem; +} + +@media (prefers-reduced-motion: reduce) { + .spinner-border, + .spinner-grow { + --bs-spinner-animation-speed: 1.5s; + } +} +.offcanvas, +.offcanvas-xxl, +.offcanvas-xl, +.offcanvas-lg, +.offcanvas-md, +.offcanvas-sm { + --bs-offcanvas-zindex: 1045; + --bs-offcanvas-width: 400px; + --bs-offcanvas-height: 30vh; + --bs-offcanvas-padding-x: 1rem; + --bs-offcanvas-padding-y: 1rem; + --bs-offcanvas-color: var(--bs-body-color); + --bs-offcanvas-bg: var(--bs-body-bg); + --bs-offcanvas-border-width: var(--bs-border-width); + --bs-offcanvas-border-color: var(--bs-border-color-translucent); + --bs-offcanvas-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); + --bs-offcanvas-transition: transform 0.3s ease-in-out; + --bs-offcanvas-title-line-height: 1.5; +} + +@media (max-width: 575.98px) { + .offcanvas-sm { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + 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; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid + var(--bs-offcanvas-border-color); + transform: translateX(-100%); + } + .offcanvas-sm.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid + var(--bs-offcanvas-border-color); + transform: translateX(100%); + } + .offcanvas-sm.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid + var(--bs-offcanvas-border-color); + transform: translateY(-100%); + } + .offcanvas-sm.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid + 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; + padding: 0; + overflow-y: visible; + background-color: transparent !important; + } +} + +@media (max-width: 767.98px) { + .offcanvas-md { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + 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; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid + var(--bs-offcanvas-border-color); + transform: translateX(-100%); + } + .offcanvas-md.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid + var(--bs-offcanvas-border-color); + transform: translateX(100%); + } + .offcanvas-md.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid + var(--bs-offcanvas-border-color); + transform: translateY(-100%); + } + .offcanvas-md.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid + 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; + padding: 0; + overflow-y: visible; + background-color: transparent !important; + } +} + +@media (max-width: 991.98px) { + .offcanvas-lg { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + 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; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid + var(--bs-offcanvas-border-color); + transform: translateX(-100%); + } + .offcanvas-lg.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid + var(--bs-offcanvas-border-color); + transform: translateX(100%); + } + .offcanvas-lg.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid + var(--bs-offcanvas-border-color); + transform: translateY(-100%); + } + .offcanvas-lg.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid + 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; + padding: 0; + overflow-y: visible; + background-color: transparent !important; + } +} + +@media (max-width: 1199.98px) { + .offcanvas-xl { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + 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; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid + var(--bs-offcanvas-border-color); + transform: translateX(-100%); + } + .offcanvas-xl.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid + var(--bs-offcanvas-border-color); + transform: translateX(100%); + } + .offcanvas-xl.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid + var(--bs-offcanvas-border-color); + transform: translateY(-100%); + } + .offcanvas-xl.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid + 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; + padding: 0; + overflow-y: visible; + background-color: transparent !important; + } +} + +@media (max-width: 1399.98px) { + .offcanvas-xxl { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + 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; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid + var(--bs-offcanvas-border-color); + transform: translateX(-100%); + } + .offcanvas-xxl.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid + var(--bs-offcanvas-border-color); + transform: translateX(100%); + } + .offcanvas-xxl.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid + var(--bs-offcanvas-border-color); + transform: translateY(-100%); + } + .offcanvas-xxl.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid + 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; + padding: 0; + overflow-y: visible; + background-color: transparent !important; + } +} + +.offcanvas { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + transition: var(--bs-offcanvas-transition); +} +@media (prefers-reduced-motion: reduce) { + .offcanvas { + transition: none; + } +} +.offcanvas.offcanvas-start { + top: 0; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid + var(--bs-offcanvas-border-color); + transform: translateX(-100%); +} +.offcanvas.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid + var(--bs-offcanvas-border-color); + transform: translateX(100%); +} +.offcanvas.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid + var(--bs-offcanvas-border-color); + transform: translateY(-100%); +} +.offcanvas.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid + var(--bs-offcanvas-border-color); + transform: translateY(100%); +} +.offcanvas.showing, +.offcanvas.show:not(.hiding) { + transform: none; +} +.offcanvas.showing, +.offcanvas.hiding, +.offcanvas.show { + visibility: visible; +} + +.offcanvas-backdrop { + position: fixed; + top: 0; + left: 0; + z-index: 1040; + width: 100vw; + height: 100vh; + background-color: #000; +} +.offcanvas-backdrop.fade { + opacity: 0; +} +.offcanvas-backdrop.show { + opacity: 0.5; +} + +.offcanvas-header { + display: flex; + align-items: center; + 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); + margin-top: calc(-0.5 * var(--bs-offcanvas-padding-y)); + margin-right: calc(-0.5 * var(--bs-offcanvas-padding-x)); + margin-bottom: calc(-0.5 * var(--bs-offcanvas-padding-y)); +} + +.offcanvas-title { + margin-bottom: 0; + line-height: var(--bs-offcanvas-title-line-height); +} + +.offcanvas-body { + flex-grow: 1; + padding: var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x); + overflow-y: auto; +} + +.placeholder { + display: inline-block; + min-height: 1em; + vertical-align: middle; + cursor: wait; + background-color: currentcolor; + opacity: 0.5; +} +.placeholder.btn::before { + display: inline-block; + content: ''; +} + +.placeholder-xs { + min-height: 0.6em; +} + +.placeholder-sm { + min-height: 0.8em; +} + +.placeholder-lg { + min-height: 1.2em; +} + +.placeholder-glow .placeholder { + animation: placeholder-glow 2s ease-in-out infinite; +} + +@keyframes placeholder-glow { + 50% { + opacity: 0.2; + } +} +.placeholder-wave { + mask-image: linear-gradient( + 130deg, + #000 55%, + rgba(0, 0, 0, 0.8) 75%, + #000 95% + ); + mask-size: 200% 100%; + animation: placeholder-wave 2s linear infinite; +} + +@keyframes placeholder-wave { + 100% { + mask-position: -200% 0%; + } +} +.clearfix::after { + display: block; + clear: both; + content: ''; +} + +.text-bg-primary { + color: #000 !important; + background-color: RGBA(49, 187, 107, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-secondary { + color: #fff !important; + background-color: RGBA(112, 112, 112, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-success { + color: #000 !important; + background-color: RGBA(49, 187, 107, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-info { + color: #000 !important; + background-color: RGBA(13, 202, 240, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-warning { + color: #000 !important; + background-color: RGBA(254, 188, 89, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-danger { + color: #fff !important; + background-color: RGBA(220, 53, 69, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-light { + color: #000 !important; + background-color: RGBA(248, 249, 250, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-dark { + color: #fff !important; + background-color: RGBA(33, 37, 41, var(--bs-bg-opacity, 1)) !important; +} + +.link-primary { + color: RGBA(var(--bs-primary-rgb), var(--bs-link-opacity, 1)) !important; + text-decoration-color: RGBA( + var(--bs-primary-rgb), + var(--bs-link-underline-opacity, 1) + ) !important; +} +.link-primary:hover, +.link-primary:focus { + color: RGBA(90, 201, 137, var(--bs-link-opacity, 1)) !important; + text-decoration-color: RGBA( + 90, + 201, + 137, + var(--bs-link-underline-opacity, 1) + ) !important; +} + +.link-secondary { + color: RGBA(var(--bs-secondary-rgb), var(--bs-link-opacity, 1)) !important; + text-decoration-color: RGBA( + var(--bs-secondary-rgb), + var(--bs-link-underline-opacity, 1) + ) !important; +} +.link-secondary:hover, +.link-secondary:focus { + color: RGBA(90, 90, 90, var(--bs-link-opacity, 1)) !important; + text-decoration-color: RGBA( + 90, + 90, + 90, + var(--bs-link-underline-opacity, 1) + ) !important; +} + +.link-success { + color: RGBA(var(--bs-success-rgb), var(--bs-link-opacity, 1)) !important; + text-decoration-color: RGBA( + var(--bs-success-rgb), + var(--bs-link-underline-opacity, 1) + ) !important; +} +.link-success:hover, +.link-success:focus { + color: RGBA(90, 201, 137, var(--bs-link-opacity, 1)) !important; + text-decoration-color: RGBA( + 90, + 201, + 137, + var(--bs-link-underline-opacity, 1) + ) !important; +} + +.link-info { + color: RGBA(var(--bs-info-rgb), var(--bs-link-opacity, 1)) !important; + text-decoration-color: RGBA( + var(--bs-info-rgb), + var(--bs-link-underline-opacity, 1) + ) !important; +} +.link-info:hover, +.link-info:focus { + color: RGBA(61, 213, 243, var(--bs-link-opacity, 1)) !important; + text-decoration-color: RGBA( + 61, + 213, + 243, + var(--bs-link-underline-opacity, 1) + ) !important; +} + +.link-warning { + color: RGBA(var(--bs-warning-rgb), var(--bs-link-opacity, 1)) !important; + text-decoration-color: RGBA( + var(--bs-warning-rgb), + var(--bs-link-underline-opacity, 1) + ) !important; +} +.link-warning:hover, +.link-warning:focus { + color: RGBA(254, 201, 122, var(--bs-link-opacity, 1)) !important; + text-decoration-color: RGBA( + 254, + 201, + 122, + var(--bs-link-underline-opacity, 1) + ) !important; +} + +.link-danger { + color: RGBA(var(--bs-danger-rgb), var(--bs-link-opacity, 1)) !important; + text-decoration-color: RGBA( + var(--bs-danger-rgb), + var(--bs-link-underline-opacity, 1) + ) !important; +} +.link-danger:hover, +.link-danger:focus { + color: RGBA(176, 42, 55, var(--bs-link-opacity, 1)) !important; + text-decoration-color: RGBA( + 176, + 42, + 55, + var(--bs-link-underline-opacity, 1) + ) !important; +} + +.link-light { + color: RGBA(var(--bs-light-rgb), var(--bs-link-opacity, 1)) !important; + text-decoration-color: RGBA( + var(--bs-light-rgb), + var(--bs-link-underline-opacity, 1) + ) !important; +} +.link-light:hover, +.link-light:focus { + color: RGBA(249, 250, 251, var(--bs-link-opacity, 1)) !important; + text-decoration-color: RGBA( + 249, + 250, + 251, + var(--bs-link-underline-opacity, 1) + ) !important; +} + +.link-dark { + color: RGBA(var(--bs-dark-rgb), var(--bs-link-opacity, 1)) !important; + text-decoration-color: RGBA( + var(--bs-dark-rgb), + var(--bs-link-underline-opacity, 1) + ) !important; +} +.link-dark:hover, +.link-dark:focus { + color: RGBA(26, 30, 33, var(--bs-link-opacity, 1)) !important; + text-decoration-color: RGBA( + 26, + 30, + 33, + var(--bs-link-underline-opacity, 1) + ) !important; +} + +.link-body-emphasis { + color: RGBA( + var(--bs-emphasis-color-rgb), + var(--bs-link-opacity, 1) + ) !important; + text-decoration-color: RGBA( + var(--bs-emphasis-color-rgb), + var(--bs-link-underline-opacity, 1) + ) !important; +} +.link-body-emphasis:hover, +.link-body-emphasis:focus { + color: RGBA( + var(--bs-emphasis-color-rgb), + var(--bs-link-opacity, 0.75) + ) !important; + text-decoration-color: RGBA( + var(--bs-emphasis-color-rgb), + var(--bs-link-underline-opacity, 0.75) + ) !important; +} + +.focus-ring:focus { + outline: 0; + box-shadow: var(--bs-focus-ring-x, 0) var(--bs-focus-ring-y, 0) + var(--bs-focus-ring-blur, 0) var(--bs-focus-ring-width) + var(--bs-focus-ring-color); +} + +.icon-link { + display: inline-flex; + gap: 0.375rem; + align-items: center; + text-decoration-color: rgba( + var(--bs-link-color-rgb), + var(--bs-link-opacity, 0.5) + ); + text-underline-offset: 0.25em; + backface-visibility: hidden; +} +.icon-link > .bi { + flex-shrink: 0; + width: 1em; + height: 1em; + fill: currentcolor; + transition: 0.2s ease-in-out transform; +} +@media (prefers-reduced-motion: reduce) { + .icon-link > .bi { + transition: none; + } +} + +.icon-link-hover:hover > .bi, +.icon-link-hover:focus-visible > .bi { + transform: var(--bs-icon-link-transform, translate3d(0.25em, 0, 0)); +} + +.ratio { + position: relative; + width: 100%; +} +.ratio::before { + display: block; + padding-top: var(--bs-aspect-ratio); + content: ''; +} +.ratio > * { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.ratio-1x1 { + --bs-aspect-ratio: 100%; +} + +.ratio-4x3 { + --bs-aspect-ratio: 75%; +} + +.ratio-16x9 { + --bs-aspect-ratio: 56.25%; +} + +.ratio-21x9 { + --bs-aspect-ratio: 42.8571428571%; +} + +.fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} + +.fixed-bottom { + position: fixed; + right: 0; + bottom: 0; + left: 0; + z-index: 1030; +} + +.sticky-top { + position: sticky; + top: 0; + z-index: 1020; +} + +.sticky-bottom { + position: sticky; + bottom: 0; + z-index: 1020; +} + +@media (min-width: 576px) { + .sticky-sm-top { + position: sticky; + 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; + align-items: center; + align-self: stretch; +} + +.vstack { + display: flex; + flex: 1 1 auto; + flex-direction: column; + align-self: stretch; +} + +.visually-hidden, +.visually-hidden-focusable:not(:focus):not(:focus-within) { + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; + overflow: hidden !important; + clip: rect(0, 0, 0, 0) !important; + white-space: nowrap !important; + border: 0 !important; +} +.visually-hidden:not(caption), +.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption) { + position: absolute !important; +} + +.stretched-link::after { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1; + content: ''; +} + +.text-truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.vr { + display: inline-block; + align-self: stretch; + width: 1px; + min-height: 1em; + background-color: currentcolor; + opacity: 0.25; +} + +.align-baseline { + vertical-align: baseline !important; +} + +.align-top { + vertical-align: top !important; +} + +.align-middle { + vertical-align: middle !important; +} + +.align-bottom { + vertical-align: bottom !important; +} + +.align-text-bottom { + vertical-align: text-bottom !important; +} + +.align-text-top { + vertical-align: text-top !important; +} + +.float-start { + float: left !important; +} + +.float-end { + float: right !important; +} + +.float-none { + float: none !important; +} + +.object-fit-contain { + object-fit: contain !important; +} + +.object-fit-cover { + object-fit: cover !important; +} + +.object-fit-fill { + object-fit: fill !important; +} + +.object-fit-scale { + object-fit: scale-down !important; +} + +.object-fit-none { + object-fit: none !important; +} + +.opacity-0 { + opacity: 0 !important; +} + +.opacity-25 { + opacity: 0.25 !important; +} + +.opacity-50 { + opacity: 0.5 !important; +} + +.opacity-75 { + opacity: 0.75 !important; +} + +.opacity-100 { + opacity: 1 !important; +} + +.overflow-auto { + overflow: auto !important; +} + +.overflow-hidden { + overflow: hidden !important; +} + +.overflow-visible { + overflow: visible !important; +} + +.overflow-scroll { + overflow: scroll !important; +} + +.overflow-x-auto { + overflow-x: auto !important; +} + +.overflow-x-hidden { + overflow-x: hidden !important; +} + +.overflow-x-visible { + overflow-x: visible !important; +} + +.overflow-x-scroll { + overflow-x: scroll !important; +} + +.overflow-y-auto { + overflow-y: auto !important; +} + +.overflow-y-hidden { + overflow-y: hidden !important; +} + +.overflow-y-visible { + overflow-y: visible !important; +} + +.overflow-y-scroll { + overflow-y: scroll !important; +} + +.d-inline { + display: inline !important; +} + +.d-inline-block { + display: inline-block !important; +} + +.d-block { + display: block !important; +} + +.d-grid { + display: grid !important; +} + +.d-inline-grid { + display: inline-grid !important; +} + +.d-table { + display: table !important; +} + +.d-table-row { + display: table-row !important; +} + +.d-table-cell { + display: table-cell !important; +} + +.d-flex { + display: flex !important; +} + +.d-inline-flex { + display: inline-flex !important; +} + +.d-none { + display: none !important; +} + +.shadow { + box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; +} + +.shadow-sm { + box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important; +} + +.shadow-lg { + box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important; +} + +.shadow-none { + box-shadow: none !important; +} + +.focus-ring-primary { + --bs-focus-ring-color: rgba( + var(--bs-primary-rgb), + var(--bs-focus-ring-opacity) + ); +} + +.focus-ring-secondary { + --bs-focus-ring-color: rgba( + var(--bs-secondary-rgb), + var(--bs-focus-ring-opacity) + ); +} + +.focus-ring-success { + --bs-focus-ring-color: rgba( + var(--bs-success-rgb), + var(--bs-focus-ring-opacity) + ); +} + +.focus-ring-info { + --bs-focus-ring-color: rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity)); +} + +.focus-ring-warning { + --bs-focus-ring-color: rgba( + var(--bs-warning-rgb), + var(--bs-focus-ring-opacity) + ); +} + +.focus-ring-danger { + --bs-focus-ring-color: rgba( + var(--bs-danger-rgb), + var(--bs-focus-ring-opacity) + ); +} + +.focus-ring-light { + --bs-focus-ring-color: rgba( + var(--bs-light-rgb), + var(--bs-focus-ring-opacity) + ); +} + +.focus-ring-dark { + --bs-focus-ring-color: rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity)); +} + +.position-static { + position: static !important; +} + +.position-relative { + position: relative !important; +} + +.position-absolute { + position: absolute !important; +} + +.position-fixed { + position: fixed !important; +} + +.position-sticky { + position: sticky !important; +} + +.top-0 { + top: 0 !important; +} + +.top-50 { + top: 50% !important; +} + +.top-100 { + top: 100% !important; +} + +.bottom-0 { + bottom: 0 !important; +} + +.bottom-50 { + bottom: 50% !important; +} + +.bottom-100 { + bottom: 100% !important; +} + +.start-0 { + left: 0 !important; +} + +.start-50 { + left: 50% !important; +} + +.start-100 { + left: 100% !important; +} + +.end-0 { + right: 0 !important; +} + +.end-50 { + right: 50% !important; +} + +.end-100 { + right: 100% !important; +} + +.translate-middle { + transform: translate(-50%, -50%) !important; +} + +.translate-middle-x { + transform: translateX(-50%) !important; +} + +.translate-middle-y { + transform: translateY(-50%) !important; +} + +.border { + border: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important; +} + +.border-0 { + border: 0 !important; +} + +.border-top { + border-top: var(--bs-border-width) var(--bs-border-style) + var(--bs-border-color) !important; +} + +.border-top-0 { + border-top: 0 !important; +} + +.border-end { + border-right: var(--bs-border-width) var(--bs-border-style) + var(--bs-border-color) !important; +} + +.border-end-0 { + border-right: 0 !important; +} + +.border-bottom { + border-bottom: var(--bs-border-width) var(--bs-border-style) + var(--bs-border-color) !important; +} + +.border-bottom-0 { + border-bottom: 0 !important; +} + +.border-start { + border-left: var(--bs-border-width) var(--bs-border-style) + var(--bs-border-color) !important; +} + +.border-start-0 { + border-left: 0 !important; +} + +.border-primary { + --bs-border-opacity: 1; + border-color: rgba( + var(--bs-primary-rgb), + var(--bs-border-opacity) + ) !important; +} + +.border-secondary { + --bs-border-opacity: 1; + border-color: rgba( + var(--bs-secondary-rgb), + var(--bs-border-opacity) + ) !important; +} + +.border-success { + --bs-border-opacity: 1; + border-color: rgba( + var(--bs-success-rgb), + var(--bs-border-opacity) + ) !important; +} + +.border-info { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-info-rgb), var(--bs-border-opacity)) !important; +} + +.border-warning { + --bs-border-opacity: 1; + border-color: rgba( + var(--bs-warning-rgb), + var(--bs-border-opacity) + ) !important; +} + +.border-danger { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-danger-rgb), var(--bs-border-opacity)) !important; +} + +.border-light { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-light-rgb), var(--bs-border-opacity)) !important; +} + +.border-dark { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-dark-rgb), var(--bs-border-opacity)) !important; +} + +.border-black { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-black-rgb), var(--bs-border-opacity)) !important; +} + +.border-white { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-white-rgb), var(--bs-border-opacity)) !important; +} + +.border-primary-subtle { + border-color: var(--bs-primary-border-subtle) !important; +} + +.border-secondary-subtle { + border-color: var(--bs-secondary-border-subtle) !important; +} + +.border-success-subtle { + border-color: var(--bs-success-border-subtle) !important; +} + +.border-info-subtle { + border-color: var(--bs-info-border-subtle) !important; +} + +.border-warning-subtle { + border-color: var(--bs-warning-border-subtle) !important; +} + +.border-danger-subtle { + border-color: var(--bs-danger-border-subtle) !important; +} + +.border-light-subtle { + border-color: var(--bs-light-border-subtle) !important; +} + +.border-dark-subtle { + border-color: var(--bs-dark-border-subtle) !important; +} + +.border-1 { + border-width: 1px !important; +} + +.border-2 { + border-width: 2px !important; +} + +.border-3 { + border-width: 3px !important; +} + +.border-4 { + border-width: 4px !important; +} + +.border-5 { + border-width: 5px !important; +} + +.border-opacity-10 { + --bs-border-opacity: 0.1; +} + +.border-opacity-25 { + --bs-border-opacity: 0.25; +} + +.border-opacity-50 { + --bs-border-opacity: 0.5; +} + +.border-opacity-75 { + --bs-border-opacity: 0.75; +} + +.border-opacity-100 { + --bs-border-opacity: 1; +} + +.w-25 { + width: 25% !important; +} + +.w-50 { + width: 50% !important; +} + +.w-75 { + width: 75% !important; +} + +.w-100 { + width: 100% !important; +} + +.w-auto { + width: auto !important; +} + +.mw-100 { + max-width: 100% !important; +} + +.vw-100 { + width: 100vw !important; +} + +.min-vw-100 { + min-width: 100vw !important; +} + +.h-25 { + height: 25% !important; +} + +.h-50 { + height: 50% !important; +} + +.h-75 { + height: 75% !important; +} + +.h-100 { + height: 100% !important; +} + +.h-auto { + height: auto !important; +} + +.mh-100 { + max-height: 100% !important; +} + +.vh-100 { + height: 100vh !important; +} + +.min-vh-100 { + min-height: 100vh !important; +} + +.flex-fill { + flex: 1 1 auto !important; +} + +.flex-row { + flex-direction: row !important; +} + +.flex-column { + flex-direction: column !important; +} + +.flex-row-reverse { + flex-direction: row-reverse !important; +} + +.flex-column-reverse { + flex-direction: column-reverse !important; +} + +.flex-grow-0 { + flex-grow: 0 !important; +} + +.flex-grow-1 { + flex-grow: 1 !important; +} + +.flex-shrink-0 { + flex-shrink: 0 !important; +} + +.flex-shrink-1 { + flex-shrink: 1 !important; +} + +.flex-wrap { + flex-wrap: wrap !important; +} + +.flex-nowrap { + flex-wrap: nowrap !important; +} + +.flex-wrap-reverse { + flex-wrap: wrap-reverse !important; +} + +.justify-content-start { + justify-content: flex-start !important; +} + +.justify-content-end { + justify-content: flex-end !important; +} + +.justify-content-center { + justify-content: center !important; +} + +.justify-content-between { + justify-content: space-between !important; +} + +.justify-content-around { + justify-content: space-around !important; +} + +.justify-content-evenly { + justify-content: space-evenly !important; +} + +.align-items-start { + align-items: flex-start !important; +} + +.align-items-end { + align-items: flex-end !important; +} + +.align-items-center { + align-items: center !important; +} + +.align-items-baseline { + align-items: baseline !important; +} + +.align-items-stretch { + align-items: stretch !important; +} + +.align-content-start { + align-content: flex-start !important; +} + +.align-content-end { + align-content: flex-end !important; +} + +.align-content-center { + align-content: center !important; +} + +.align-content-between { + align-content: space-between !important; +} + +.align-content-around { + align-content: space-around !important; +} + +.align-content-stretch { + align-content: stretch !important; +} + +.align-self-auto { + align-self: auto !important; +} + +.align-self-start { + align-self: flex-start !important; +} + +.align-self-end { + align-self: flex-end !important; +} + +.align-self-center { + align-self: center !important; +} + +.align-self-baseline { + align-self: baseline !important; +} + +.align-self-stretch { + align-self: stretch !important; +} + +.order-first { + order: -1 !important; +} + +.order-0 { + order: 0 !important; +} + +.order-1 { + order: 1 !important; +} + +.order-2 { + order: 2 !important; +} + +.order-3 { + order: 3 !important; +} + +.order-4 { + order: 4 !important; +} + +.order-5 { + order: 5 !important; +} + +.order-last { + order: 6 !important; +} + +.m-0 { + margin: 0 !important; +} + +.m-1 { + margin: 0.25rem !important; +} + +.m-2 { + margin: 0.5rem !important; +} + +.m-3 { + margin: 1rem !important; +} + +.m-4 { + margin: 1.5rem !important; +} + +.m-5 { + margin: 3rem !important; +} + +.m-auto { + margin: auto !important; +} + +.mx-0 { + margin-right: 0 !important; + margin-left: 0 !important; +} + +.mx-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; +} + +.mx-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; +} + +.mx-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; +} + +.mx-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; +} + +.mx-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; +} + +.mx-auto { + margin-right: auto !important; + margin-left: auto !important; +} + +.my-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +.my-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; +} + +.my-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; +} + +.my-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; +} + +.my-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; +} + +.my-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; +} + +.my-auto { + margin-top: auto !important; + margin-bottom: auto !important; +} + +.mt-0 { + margin-top: 0 !important; +} + +.mt-1 { + margin-top: 0.25rem !important; +} + +.mt-2 { + margin-top: 0.5rem !important; +} + +.mt-3 { + margin-top: 1rem !important; +} + +.mt-4 { + margin-top: 1.5rem !important; +} + +.mt-5 { + margin-top: 3rem !important; +} + +.mt-auto { + margin-top: auto !important; +} + +.me-0 { + margin-right: 0 !important; +} + +.me-1 { + margin-right: 0.25rem !important; +} + +.me-2 { + margin-right: 0.5rem !important; +} + +.me-3 { + margin-right: 1rem !important; +} + +.me-4 { + margin-right: 1.5rem !important; +} + +.me-5 { + margin-right: 3rem !important; +} + +.me-auto { + margin-right: auto !important; +} + +.mb-0 { + margin-bottom: 0 !important; +} + +.mb-1 { + margin-bottom: 0.25rem !important; +} + +.mb-2 { + margin-bottom: 0.5rem !important; +} + +.mb-3 { + margin-bottom: 1rem !important; +} + +.mb-4 { + margin-bottom: 1.5rem !important; +} + +.mb-5 { + margin-bottom: 3rem !important; +} + +.mb-auto { + margin-bottom: auto !important; +} + +.ms-0 { + margin-left: 0 !important; +} + +.ms-1 { + margin-left: 0.25rem !important; +} + +.ms-2 { + margin-left: 0.5rem !important; +} + +.ms-3 { + margin-left: 1rem !important; +} + +.ms-4 { + margin-left: 1.5rem !important; +} + +.ms-5 { + margin-left: 3rem !important; +} + +.ms-auto { + margin-left: auto !important; +} + +.p-0 { + padding: 0 !important; +} + +.p-1 { + padding: 0.25rem !important; +} + +.p-2 { + padding: 0.5rem !important; +} + +.p-3 { + padding: 1rem !important; +} + +.p-4 { + padding: 1.5rem !important; +} + +.p-5 { + padding: 3rem !important; +} + +.px-0 { + padding-right: 0 !important; + padding-left: 0 !important; +} + +.px-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; +} + +.px-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; +} + +.px-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; +} + +.px-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; +} + +.px-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; +} + +.py-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; +} + +.py-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; +} + +.py-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; +} + +.py-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; +} + +.py-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; +} + +.py-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; +} + +.pt-0 { + padding-top: 0 !important; +} + +.pt-1 { + padding-top: 0.25rem !important; +} + +.pt-2 { + padding-top: 0.5rem !important; +} + +.pt-3 { + padding-top: 1rem !important; +} + +.pt-4 { + padding-top: 1.5rem !important; +} + +.pt-5 { + padding-top: 3rem !important; +} + +.pe-0 { + padding-right: 0 !important; +} + +.pe-1 { + padding-right: 0.25rem !important; +} + +.pe-2 { + padding-right: 0.5rem !important; +} + +.pe-3 { + padding-right: 1rem !important; +} + +.pe-4 { + padding-right: 1.5rem !important; +} + +.pe-5 { + padding-right: 3rem !important; +} + +.pb-0 { + padding-bottom: 0 !important; +} + +.pb-1 { + padding-bottom: 0.25rem !important; +} + +.pb-2 { + padding-bottom: 0.5rem !important; +} + +.pb-3 { + padding-bottom: 1rem !important; +} + +.pb-4 { + padding-bottom: 1.5rem !important; +} + +.pb-5 { + padding-bottom: 3rem !important; +} + +.ps-0 { + padding-left: 0 !important; +} + +.ps-1 { + padding-left: 0.25rem !important; +} + +.ps-2 { + padding-left: 0.5rem !important; +} + +.ps-3 { + padding-left: 1rem !important; +} + +.ps-4 { + padding-left: 1.5rem !important; +} + +.ps-5 { + padding-left: 3rem !important; +} + +.gap-0 { + gap: 0 !important; +} + +.gap-1 { + gap: 0.25rem !important; +} + +.gap-2 { + gap: 0.5rem !important; +} + +.gap-3 { + gap: 1rem !important; +} + +.gap-4 { + gap: 1.5rem !important; +} + +.gap-5 { + gap: 3rem !important; +} + +.row-gap-0 { + row-gap: 0 !important; +} + +.row-gap-1 { + row-gap: 0.25rem !important; +} + +.row-gap-2 { + row-gap: 0.5rem !important; +} + +.row-gap-3 { + row-gap: 1rem !important; +} + +.row-gap-4 { + row-gap: 1.5rem !important; +} + +.row-gap-5 { + row-gap: 3rem !important; +} + +.column-gap-0 { + column-gap: 0 !important; +} + +.column-gap-1 { + column-gap: 0.25rem !important; +} + +.column-gap-2 { + column-gap: 0.5rem !important; +} + +.column-gap-3 { + column-gap: 1rem !important; +} + +.column-gap-4 { + column-gap: 1.5rem !important; +} + +.column-gap-5 { + column-gap: 3rem !important; +} + +.font-monospace { + font-family: var(--bs-font-monospace) !important; +} + +.fs-1 { + font-size: calc(1.375rem + 1.5vw) !important; +} + +.fs-2 { + font-size: calc(1.325rem + 0.9vw) !important; +} + +.fs-3 { + font-size: calc(1.3rem + 0.6vw) !important; +} + +.fs-4 { + font-size: calc(1.275rem + 0.3vw) !important; +} + +.fs-5 { + font-size: 1.25rem !important; +} + +.fs-6 { + font-size: 1rem !important; +} + +.fst-italic { + font-style: italic !important; +} + +.fst-normal { + font-style: normal !important; +} + +.fw-lighter { + font-weight: lighter !important; +} + +.fw-light { + font-weight: 300 !important; +} + +.fw-normal { + font-weight: 400 !important; +} + +.fw-medium { + font-weight: 500 !important; +} + +.fw-semibold { + font-weight: 600 !important; +} + +.fw-bold { + font-weight: 700 !important; +} + +.fw-bolder { + font-weight: bolder !important; +} + +.lh-1 { + line-height: 1 !important; +} + +.lh-sm { + line-height: 1.25 !important; +} + +.lh-base { + line-height: 1.5 !important; +} + +.lh-lg { + line-height: 2 !important; +} + +.text-start { + text-align: left !important; +} + +.text-end { + text-align: right !important; +} + +.text-center { + text-align: center !important; +} + +.text-decoration-none { + text-decoration: none !important; +} + +.text-decoration-underline { + text-decoration: underline !important; +} + +.text-decoration-line-through { + text-decoration: line-through !important; +} + +.text-lowercase { + text-transform: lowercase !important; +} + +.text-uppercase { + text-transform: uppercase !important; +} + +.text-capitalize { + text-transform: capitalize !important; +} + +.text-wrap { + white-space: normal !important; +} + +.text-nowrap { + white-space: nowrap !important; +} + +/* rtl:begin:remove */ +.text-break { + word-wrap: break-word !important; + word-break: break-word !important; +} + +/* rtl:end:remove */ +.text-primary { + --bs-text-opacity: 1; + color: rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important; +} + +.text-secondary { + --bs-text-opacity: 1; + color: rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important; +} + +.text-success { + --bs-text-opacity: 1; + color: rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important; +} + +.text-info { + --bs-text-opacity: 1; + color: rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important; +} + +.text-warning { + --bs-text-opacity: 1; + color: rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important; +} + +.text-danger { + --bs-text-opacity: 1; + color: rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important; +} + +.text-light { + --bs-text-opacity: 1; + color: rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important; +} + +.text-dark { + --bs-text-opacity: 1; + color: rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important; +} + +.text-black { + --bs-text-opacity: 1; + color: rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important; +} + +.text-white { + --bs-text-opacity: 1; + color: rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important; +} + +.text-body { + --bs-text-opacity: 1; + color: rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important; +} + +.text-muted { + --bs-text-opacity: 1; + color: var(--bs-secondary-color) !important; +} + +.text-black-50 { + --bs-text-opacity: 1; + color: rgba(0, 0, 0, 0.5) !important; +} + +.text-white-50 { + --bs-text-opacity: 1; + color: rgba(255, 255, 255, 0.5) !important; +} + +.text-body-secondary { + --bs-text-opacity: 1; + color: var(--bs-secondary-color) !important; +} + +.text-body-tertiary { + --bs-text-opacity: 1; + color: var(--bs-tertiary-color) !important; +} + +.text-body-emphasis { + --bs-text-opacity: 1; + color: var(--bs-emphasis-color) !important; +} + +.text-reset { + --bs-text-opacity: 1; + color: inherit !important; +} + +.text-opacity-25 { + --bs-text-opacity: 0.25; +} + +.text-opacity-50 { + --bs-text-opacity: 0.5; +} + +.text-opacity-75 { + --bs-text-opacity: 0.75; +} + +.text-opacity-100 { + --bs-text-opacity: 1; +} + +.text-primary-emphasis { + color: var(--bs-primary-text-emphasis) !important; +} + +.text-secondary-emphasis { + color: var(--bs-secondary-text-emphasis) !important; +} + +.text-success-emphasis { + color: var(--bs-success-text-emphasis) !important; +} + +.text-info-emphasis { + color: var(--bs-info-text-emphasis) !important; +} + +.text-warning-emphasis { + color: var(--bs-warning-text-emphasis) !important; +} + +.text-danger-emphasis { + color: var(--bs-danger-text-emphasis) !important; +} + +.text-light-emphasis { + color: var(--bs-light-text-emphasis) !important; +} + +.text-dark-emphasis { + color: var(--bs-dark-text-emphasis) !important; +} + +.link-opacity-10 { + --bs-link-opacity: 0.1; +} + +.link-opacity-10-hover:hover { + --bs-link-opacity: 0.1; +} + +.link-opacity-25 { + --bs-link-opacity: 0.25; +} + +.link-opacity-25-hover:hover { + --bs-link-opacity: 0.25; +} + +.link-opacity-50 { + --bs-link-opacity: 0.5; +} + +.link-opacity-50-hover:hover { + --bs-link-opacity: 0.5; +} + +.link-opacity-75 { + --bs-link-opacity: 0.75; +} + +.link-opacity-75-hover:hover { + --bs-link-opacity: 0.75; +} + +.link-opacity-100 { + --bs-link-opacity: 1; +} + +.link-opacity-100-hover:hover { + --bs-link-opacity: 1; +} + +.link-offset-1 { + text-underline-offset: 0.125em !important; +} + +.link-offset-1-hover:hover { + text-underline-offset: 0.125em !important; +} + +.link-offset-2 { + text-underline-offset: 0.25em !important; +} + +.link-offset-2-hover:hover { + text-underline-offset: 0.25em !important; +} + +.link-offset-3 { + text-underline-offset: 0.375em !important; +} + +.link-offset-3-hover:hover { + text-underline-offset: 0.375em !important; +} + +.link-underline-primary { + --bs-link-underline-opacity: 1; + text-decoration-color: rgba( + var(--bs-primary-rgb), + var(--bs-link-underline-opacity) + ) !important; +} + +.link-underline-secondary { + --bs-link-underline-opacity: 1; + text-decoration-color: rgba( + var(--bs-secondary-rgb), + var(--bs-link-underline-opacity) + ) !important; +} + +.link-underline-success { + --bs-link-underline-opacity: 1; + text-decoration-color: rgba( + var(--bs-success-rgb), + var(--bs-link-underline-opacity) + ) !important; +} + +.link-underline-info { + --bs-link-underline-opacity: 1; + text-decoration-color: rgba( + var(--bs-info-rgb), + var(--bs-link-underline-opacity) + ) !important; +} + +.link-underline-warning { + --bs-link-underline-opacity: 1; + text-decoration-color: rgba( + var(--bs-warning-rgb), + var(--bs-link-underline-opacity) + ) !important; +} + +.link-underline-danger { + --bs-link-underline-opacity: 1; + text-decoration-color: rgba( + var(--bs-danger-rgb), + var(--bs-link-underline-opacity) + ) !important; +} + +.link-underline-light { + --bs-link-underline-opacity: 1; + text-decoration-color: rgba( + var(--bs-light-rgb), + var(--bs-link-underline-opacity) + ) !important; +} + +.link-underline-dark { + --bs-link-underline-opacity: 1; + text-decoration-color: rgba( + var(--bs-dark-rgb), + var(--bs-link-underline-opacity) + ) !important; +} + +.link-underline { + --bs-link-underline-opacity: 1; + text-decoration-color: rgba( + var(--bs-link-color-rgb), + var(--bs-link-underline-opacity, 1) + ) !important; +} + +.link-underline-opacity-0 { + --bs-link-underline-opacity: 0; +} + +.link-underline-opacity-0-hover:hover { + --bs-link-underline-opacity: 0; +} + +.link-underline-opacity-10 { + --bs-link-underline-opacity: 0.1; +} + +.link-underline-opacity-10-hover:hover { + --bs-link-underline-opacity: 0.1; +} + +.link-underline-opacity-25 { + --bs-link-underline-opacity: 0.25; +} + +.link-underline-opacity-25-hover:hover { + --bs-link-underline-opacity: 0.25; +} + +.link-underline-opacity-50 { + --bs-link-underline-opacity: 0.5; +} + +.link-underline-opacity-50-hover:hover { + --bs-link-underline-opacity: 0.5; +} + +.link-underline-opacity-75 { + --bs-link-underline-opacity: 0.75; +} + +.link-underline-opacity-75-hover:hover { + --bs-link-underline-opacity: 0.75; +} + +.link-underline-opacity-100 { + --bs-link-underline-opacity: 1; +} + +.link-underline-opacity-100-hover:hover { + --bs-link-underline-opacity: 1; +} + +.bg-primary { + --bs-bg-opacity: 1; + background-color: rgba( + var(--bs-primary-rgb), + var(--bs-bg-opacity) + ) !important; +} + +.bg-secondary { + --bs-bg-opacity: 1; + background-color: rgba( + var(--bs-secondary-rgb), + var(--bs-bg-opacity) + ) !important; +} + +.bg-success { + --bs-bg-opacity: 1; + background-color: rgba( + var(--bs-success-rgb), + var(--bs-bg-opacity) + ) !important; +} + +.bg-info { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-warning { + --bs-bg-opacity: 1; + background-color: rgba( + var(--bs-warning-rgb), + var(--bs-bg-opacity) + ) !important; +} + +.bg-danger { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-light { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-dark { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-black { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-white { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-body { + --bs-bg-opacity: 1; + background-color: rgba( + var(--bs-body-bg-rgb), + var(--bs-bg-opacity) + ) !important; +} + +.bg-transparent { + --bs-bg-opacity: 1; + background-color: transparent !important; +} + +.bg-body-secondary { + --bs-bg-opacity: 1; + background-color: rgba( + var(--bs-secondary-bg-rgb), + var(--bs-bg-opacity) + ) !important; +} + +.bg-body-tertiary { + --bs-bg-opacity: 1; + background-color: rgba( + var(--bs-tertiary-bg-rgb), + var(--bs-bg-opacity) + ) !important; +} + +.bg-opacity-10 { + --bs-bg-opacity: 0.1; +} + +.bg-opacity-25 { + --bs-bg-opacity: 0.25; +} + +.bg-opacity-50 { + --bs-bg-opacity: 0.5; +} + +.bg-opacity-75 { + --bs-bg-opacity: 0.75; +} + +.bg-opacity-100 { + --bs-bg-opacity: 1; +} + +.bg-primary-subtle { + background-color: var(--bs-primary-bg-subtle) !important; +} + +.bg-secondary-subtle { + background-color: var(--bs-secondary-bg-subtle) !important; +} + +.bg-success-subtle { + background-color: var(--bs-success-bg-subtle) !important; +} + +.bg-info-subtle { + background-color: var(--bs-info-bg-subtle) !important; +} + +.bg-warning-subtle { + background-color: var(--bs-warning-bg-subtle) !important; +} + +.bg-danger-subtle { + background-color: var(--bs-danger-bg-subtle) !important; +} + +.bg-light-subtle { + background-color: var(--bs-light-bg-subtle) !important; +} + +.bg-dark-subtle { + background-color: var(--bs-dark-bg-subtle) !important; +} + +.bg-gradient { + background-image: var(--bs-gradient) !important; +} + +.user-select-all { + user-select: all !important; +} + +.user-select-auto { + user-select: auto !important; +} + +.user-select-none { + user-select: none !important; +} + +.pe-none { + pointer-events: none !important; +} + +.pe-auto { + pointer-events: auto !important; +} + +.rounded { + border-radius: var(--bs-border-radius) !important; +} + +.rounded-0 { + border-radius: 0 !important; +} + +.rounded-1 { + border-radius: var(--bs-border-radius-sm) !important; +} + +.rounded-2 { + border-radius: var(--bs-border-radius) !important; +} + +.rounded-3 { + border-radius: var(--bs-border-radius-lg) !important; +} + +.rounded-4 { + border-radius: var(--bs-border-radius-xl) !important; +} + +.rounded-5 { + border-radius: var(--bs-border-radius-xxl) !important; +} + +.rounded-circle { + border-radius: 50% !important; +} + +.rounded-pill { + border-radius: var(--bs-border-radius-pill) !important; +} + +.rounded-top { + border-top-left-radius: var(--bs-border-radius) !important; + border-top-right-radius: var(--bs-border-radius) !important; +} + +.rounded-top-0 { + border-top-left-radius: 0 !important; + border-top-right-radius: 0 !important; +} + +.rounded-top-1 { + border-top-left-radius: var(--bs-border-radius-sm) !important; + border-top-right-radius: var(--bs-border-radius-sm) !important; +} + +.rounded-top-2 { + border-top-left-radius: var(--bs-border-radius) !important; + border-top-right-radius: var(--bs-border-radius) !important; +} + +.rounded-top-3 { + border-top-left-radius: var(--bs-border-radius-lg) !important; + border-top-right-radius: var(--bs-border-radius-lg) !important; +} + +.rounded-top-4 { + border-top-left-radius: var(--bs-border-radius-xl) !important; + border-top-right-radius: var(--bs-border-radius-xl) !important; +} + +.rounded-top-5 { + border-top-left-radius: var(--bs-border-radius-xxl) !important; + border-top-right-radius: var(--bs-border-radius-xxl) !important; +} + +.rounded-top-circle { + border-top-left-radius: 50% !important; + border-top-right-radius: 50% !important; +} + +.rounded-top-pill { + border-top-left-radius: var(--bs-border-radius-pill) !important; + border-top-right-radius: var(--bs-border-radius-pill) !important; +} + +.rounded-end { + border-top-right-radius: var(--bs-border-radius) !important; + border-bottom-right-radius: var(--bs-border-radius) !important; +} + +.rounded-end-0 { + border-top-right-radius: 0 !important; + border-bottom-right-radius: 0 !important; +} + +.rounded-end-1 { + border-top-right-radius: var(--bs-border-radius-sm) !important; + border-bottom-right-radius: var(--bs-border-radius-sm) !important; +} + +.rounded-end-2 { + border-top-right-radius: var(--bs-border-radius) !important; + border-bottom-right-radius: var(--bs-border-radius) !important; +} + +.rounded-end-3 { + border-top-right-radius: var(--bs-border-radius-lg) !important; + border-bottom-right-radius: var(--bs-border-radius-lg) !important; +} + +.rounded-end-4 { + border-top-right-radius: var(--bs-border-radius-xl) !important; + border-bottom-right-radius: var(--bs-border-radius-xl) !important; +} + +.rounded-end-5 { + border-top-right-radius: var(--bs-border-radius-xxl) !important; + border-bottom-right-radius: var(--bs-border-radius-xxl) !important; +} + +.rounded-end-circle { + border-top-right-radius: 50% !important; + border-bottom-right-radius: 50% !important; +} + +.rounded-end-pill { + border-top-right-radius: var(--bs-border-radius-pill) !important; + border-bottom-right-radius: var(--bs-border-radius-pill) !important; +} + +.rounded-bottom { + border-bottom-right-radius: var(--bs-border-radius) !important; + border-bottom-left-radius: var(--bs-border-radius) !important; +} + +.rounded-bottom-0 { + border-bottom-right-radius: 0 !important; + border-bottom-left-radius: 0 !important; +} + +.rounded-bottom-1 { + border-bottom-right-radius: var(--bs-border-radius-sm) !important; + border-bottom-left-radius: var(--bs-border-radius-sm) !important; +} + +.rounded-bottom-2 { + border-bottom-right-radius: var(--bs-border-radius) !important; + border-bottom-left-radius: var(--bs-border-radius) !important; +} + +.rounded-bottom-3 { + border-bottom-right-radius: var(--bs-border-radius-lg) !important; + border-bottom-left-radius: var(--bs-border-radius-lg) !important; +} + +.rounded-bottom-4 { + border-bottom-right-radius: var(--bs-border-radius-xl) !important; + border-bottom-left-radius: var(--bs-border-radius-xl) !important; +} + +.rounded-bottom-5 { + border-bottom-right-radius: var(--bs-border-radius-xxl) !important; + border-bottom-left-radius: var(--bs-border-radius-xxl) !important; +} + +.rounded-bottom-circle { + border-bottom-right-radius: 50% !important; + border-bottom-left-radius: 50% !important; +} + +.rounded-bottom-pill { + border-bottom-right-radius: var(--bs-border-radius-pill) !important; + border-bottom-left-radius: var(--bs-border-radius-pill) !important; +} + +.rounded-start { + border-bottom-left-radius: var(--bs-border-radius) !important; + border-top-left-radius: var(--bs-border-radius) !important; +} + +.rounded-start-0 { + border-bottom-left-radius: 0 !important; + border-top-left-radius: 0 !important; +} + +.rounded-start-1 { + border-bottom-left-radius: var(--bs-border-radius-sm) !important; + border-top-left-radius: var(--bs-border-radius-sm) !important; +} + +.rounded-start-2 { + border-bottom-left-radius: var(--bs-border-radius) !important; + border-top-left-radius: var(--bs-border-radius) !important; +} + +.rounded-start-3 { + border-bottom-left-radius: var(--bs-border-radius-lg) !important; + border-top-left-radius: var(--bs-border-radius-lg) !important; +} + +.rounded-start-4 { + border-bottom-left-radius: var(--bs-border-radius-xl) !important; + border-top-left-radius: var(--bs-border-radius-xl) !important; +} + +.rounded-start-5 { + border-bottom-left-radius: var(--bs-border-radius-xxl) !important; + border-top-left-radius: var(--bs-border-radius-xxl) !important; +} + +.rounded-start-circle { + border-bottom-left-radius: 50% !important; + border-top-left-radius: 50% !important; +} + +.rounded-start-pill { + border-bottom-left-radius: var(--bs-border-radius-pill) !important; + border-top-left-radius: var(--bs-border-radius-pill) !important; +} + +.visible { + visibility: visible !important; +} + +.invisible { + visibility: hidden !important; +} + +.z-n1 { + z-index: -1 !important; +} + +.z-0 { + z-index: 0 !important; +} + +.z-1 { + z-index: 1 !important; +} + +.z-2 { + z-index: 2 !important; +} + +.z-3 { + z-index: 3 !important; +} + +@media (min-width: 576px) { + .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 + ----------- + This file is used to import all partial scss files in the project. + It is used to compile the final CSS file to the CSS folder as main.css . + + ========= Table of Contents ========= + 1. Components + 2. Content + 3. Forms + 4. Utilities + 5. General + 6. Colors + + */ +/* + + 1. COMPONENTS + + */ +.btn-primary, +.btn-secondary, +.btn-success, +.btn-warning, +.btn-info { + color: #fff; +} +.btn-primary:hover, +.btn-primary:active, +.btn-secondary:hover, +.btn-secondary:active, +.btn-success:hover, +.btn-success:active, +.btn-warning:hover, +.btn-warning:active, +.btn-info:hover, +.btn-info:active { + color: #fff !important; +} + +.btn-outline-primary:hover, +.btn-outline-primary:active, +.btn-outline-secondary:hover, +.btn-outline-secondary:active, +.btn-outline-success:hover, +.btn-outline-success:active, +.btn-outline-warning:hover, +.btn-outline-warning:active, +.btn-outline-info:hover, +.btn-outline-info:active { + color: #fff !important; +} + +@keyframes progress-bar-stripes { + 0% { + 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 + + */ +/* + DISPLAY SASS VARIABLES + */ +/* + DISPLAY SASS VARIABLES + */ +/* + + 3. FORMS + + */ +/* + + 4. UTILITIES + + */ +/* + + 5. General + + */ +:root { + --bs-body-font-family: Arial, Helvetica, sans-serif; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html { + overflow-x: hidden; +} + +body { + background-color: var(--bs-body-bg); +} + +#root { + min-height: 100vh; + background-color: #f2f7ff; +} + +input[type='checkbox'] { + transform: scale(1.5); +} + +.form-switch { + padding-left: 3rem; +} + +input[type='file']::file-selector-button { + background: var(--bs-gray-400); +} + +.shimmer { + animation-duration: 2.2s; + animation-fill-mode: forwards; + animation-iteration-count: infinite; + animation-name: shimmer; + animation-timing-function: linear; + background: var(--bs-gray-200); + background: linear-gradient(to right, #f6f6f6 8%, #f0f0f0 18%, #f6f6f6 33%); + background-size: 1200px 100%; +} + +@-webkit-keyframes shimmer { + 0% { + background-position: -100% 0; + } + 100% { + background-position: 100% 0; + } +} +@keyframes shimmer { + 0% { + background-position: -1200px 0; + } + 100% { + background-position: 1200px 0; + } +} +/* + + 6. COLORS + +*/ + +/*# sourceMappingURL=app.css.map */ diff --git a/src/assets/css/app.css.map b/src/assets/css/app.css.map new file mode 100644 index 0000000000..00a8ba5443 --- /dev/null +++ b/src/assets/css/app.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["../../../node_modules/bootstrap/scss/mixins/_banner.scss","../../../node_modules/bootstrap/scss/_root.scss","../../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../../node_modules/bootstrap/scss/mixins/_color-mode.scss","../../../node_modules/bootstrap/scss/_reboot.scss","../../../node_modules/bootstrap/scss/_variables.scss","../scss/_variables.scss","../../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../../node_modules/bootstrap/scss/_type.scss","../../../node_modules/bootstrap/scss/mixins/_lists.scss","../../../node_modules/bootstrap/scss/_images.scss","../../../node_modules/bootstrap/scss/mixins/_image.scss","../../../node_modules/bootstrap/scss/_containers.scss","../../../node_modules/bootstrap/scss/mixins/_container.scss","../../../node_modules/bootstrap/scss/mixins/_breakpoints.scss","../../../node_modules/bootstrap/scss/_grid.scss","../../../node_modules/bootstrap/scss/mixins/_grid.scss","../../../node_modules/bootstrap/scss/_tables.scss","../../../node_modules/bootstrap/scss/mixins/_table-variants.scss","../../../node_modules/bootstrap/scss/forms/_labels.scss","../../../node_modules/bootstrap/scss/forms/_form-text.scss","../../../node_modules/bootstrap/scss/forms/_form-control.scss","../../../node_modules/bootstrap/scss/mixins/_transition.scss","../../../node_modules/bootstrap/scss/mixins/_gradients.scss","../../../node_modules/bootstrap/scss/forms/_form-select.scss","../../../node_modules/bootstrap/scss/forms/_form-check.scss","../../../node_modules/bootstrap/scss/forms/_form-range.scss","../../../node_modules/bootstrap/scss/forms/_floating-labels.scss","../../../node_modules/bootstrap/scss/forms/_input-group.scss","../../../node_modules/bootstrap/scss/mixins/_forms.scss","../../../node_modules/bootstrap/scss/_buttons.scss","../../../node_modules/bootstrap/scss/mixins/_buttons.scss","../../../node_modules/bootstrap/scss/_transitions.scss","../../../node_modules/bootstrap/scss/_dropdown.scss","../../../node_modules/bootstrap/scss/mixins/_caret.scss","../../../node_modules/bootstrap/scss/_button-group.scss","../../../node_modules/bootstrap/scss/_nav.scss","../../../node_modules/bootstrap/scss/_navbar.scss","../../../node_modules/bootstrap/scss/_card.scss","../../../node_modules/bootstrap/scss/_accordion.scss","../../../node_modules/bootstrap/scss/_breadcrumb.scss","../../../node_modules/bootstrap/scss/_pagination.scss","../../../node_modules/bootstrap/scss/mixins/_pagination.scss","../../../node_modules/bootstrap/scss/_badge.scss","../../../node_modules/bootstrap/scss/_alert.scss","../../../node_modules/bootstrap/scss/_progress.scss","../../../node_modules/bootstrap/scss/_list-group.scss","../../../node_modules/bootstrap/scss/_close.scss","../../../node_modules/bootstrap/scss/_toasts.scss","../../../node_modules/bootstrap/scss/_modal.scss","../../../node_modules/bootstrap/scss/mixins/_backdrop.scss","../../../node_modules/bootstrap/scss/_tooltip.scss","../../../node_modules/bootstrap/scss/mixins/_reset-text.scss","../../../node_modules/bootstrap/scss/_popover.scss","../../../node_modules/bootstrap/scss/_carousel.scss","../../../node_modules/bootstrap/scss/mixins/_clearfix.scss","../../../node_modules/bootstrap/scss/_spinners.scss","../../../node_modules/bootstrap/scss/_offcanvas.scss","../../../node_modules/bootstrap/scss/_placeholders.scss","../../../node_modules/bootstrap/scss/helpers/_color-bg.scss","../../../node_modules/bootstrap/scss/helpers/_colored-links.scss","../../../node_modules/bootstrap/scss/helpers/_focus-ring.scss","../../../node_modules/bootstrap/scss/helpers/_icon-link.scss","../../../node_modules/bootstrap/scss/helpers/_ratio.scss","../../../node_modules/bootstrap/scss/helpers/_position.scss","../../../node_modules/bootstrap/scss/helpers/_stacks.scss","../../../node_modules/bootstrap/scss/helpers/_visually-hidden.scss","../../../node_modules/bootstrap/scss/mixins/_visually-hidden.scss","../../../node_modules/bootstrap/scss/helpers/_stretched-link.scss","../../../node_modules/bootstrap/scss/helpers/_text-truncation.scss","../../../node_modules/bootstrap/scss/mixins/_text-truncate.scss","../../../node_modules/bootstrap/scss/helpers/_vr.scss","../../../node_modules/bootstrap/scss/mixins/_utilities.scss","../../../node_modules/bootstrap/scss/utilities/_api.scss","../scss/_talawa.scss","../scss/components/_buttons.scss","../scss/components/_progress.scss","../scss/components/_spinners.scss","../scss/content/_typography.scss","../scss/_general.scss"],"names":[],"mappings":";AACE;AAAA;AAAA;AAAA;AAAA;ACDF;AAAA;EASI;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAIA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAIA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAIA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAIA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAIA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAIA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAGF;EACA;EAMA;EACA;EACA;EAOA;EC2OI,qBALI;EDpOR;EACA;EAKA;EACA;EACA;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EAGA;EAEA;EACA;EACA;EAEA;EACA;EAMA;EACA;EAGA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EAIA;EACA;EACA;EAIA;EACA;EACA;EACA;;;AE/GE;EFqHA;EAGA;EACA;EACA;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EAGE;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAIA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAIA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAGF;EAEA;EACA;EACA;EACA;EAEA;EAEA;EACA;EAEA;EACA;EACA;EACA;;;AGrKJ;AAAA;AAAA;EAGE;;;AAeE;EANJ;IAOM;;;;AAcN;EACE;EACA;EF6OI,WALI;EEtOR;EACA;EACA;EACA;EACA;EACA;EACA;;;AASF;EACE;EACA,OCmnB4B;EDlnB5B;EACA;EACA,SCynB4B;;;AD/mB9B;EACE;EACA,eCwjB4B;EDrjB5B,aCwjB4B;EDvjB5B,aCwjB4B;EDvjB5B;;;AAGF;EFuMQ;;AA5JJ;EE3CJ;IF8MQ;;;;AEzMR;EFkMQ;;AA5JJ;EEtCJ;IFyMQ;;;;AEpMR;EF6LQ;;AA5JJ;EEjCJ;IFoMQ;;;;AE/LR;EFwLQ;;AA5JJ;EE5BJ;IF+LQ;;;;AE1LR;EF+KM,WALI;;;AErKV;EF0KM,WALI;;;AE1JV;EACE;EACA,eCwV0B;;;AD9U5B;EACE;EACA;EACA;;;AAMF;EACE;EACA;EACA;;;AAMF;AAAA;EAEE;;;AAGF;AAAA;AAAA;EAGE;EACA;;;AAGF;AAAA;AAAA;AAAA;EAIE;;;AAGF;EACE,aC6b4B;;;ADxb9B;EACE;EACA;;;AAMF;EACE;;;AAQF;AAAA;EAEE,aCsa4B;;;AD9Z9B;EF6EM,WALI;;;AEjEV;EACE,SCif4B;EDhf5B;;;AASF;AAAA;EAEE;EFyDI,WALI;EElDR;EACA;;;AAGF;EAAM;;;AACN;EAAM;;;AAKN;EACE;EACA,iBE9NgB;;AFgOhB;EACE;;;AAWF;EAEE;EACA;;;AAOJ;AAAA;AAAA;AAAA;EAIE,aCiV4B;EHlUxB,WALI;;;AEFV;EACE;EACA;EACA;EACA;EFGI,WALI;;AEOR;EFFI,WALI;EESN;EACA;;;AAIJ;EFTM,WALI;EEgBR;EACA;;AAGA;EACE;;;AAIJ;EACE;EFrBI,WALI;EE4BR,OCo5CkC;EDn5ClC,kBCo5CkC;EExrDhC;;AHuSF;EACE;EF5BE,WALI;;;AE4CV;EACE;;;AAMF;AAAA;EAEE;;;AAQF;EACE;EACA;;;AAGF;EACE,aCwX4B;EDvX5B,gBCuX4B;EDtX5B,OCwZ4B;EDvZ5B;;;AAOF;EAEE;EACA;;;AAGF;AAAA;AAAA;AAAA;AAAA;AAAA;EAME;EACA;EACA;;;AAQF;EACE;;;AAMF;EAEE;;;AAQF;EACE;;;AAKF;AAAA;AAAA;AAAA;AAAA;EAKE;EACA;EF3HI,WALI;EEkIR;;;AAIF;AAAA;EAEE;;;AAKF;EACE;;;AAGF;EAGE;;AAGA;EACE;;;AAOJ;EACE;;;AAQF;AAAA;AAAA;AAAA;EAIE;;AAGE;AAAA;AAAA;AAAA;EACE;;;AAON;EACE;EACA;;;AAKF;EACE;;;AAUF;EACE;EACA;EACA;EACA;;;AAQF;EACE;EACA;EACA;EACA,eCgN4B;EHhatB;EEmNN;;AF/WE;EEwWJ;IFrMQ;;;AE8MN;EACE;;;AAOJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAOE;;;AAGF;EACE;;;AASF;EACE;EACA;;;AAQF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWA;EACE;;;AAKF;EACE;;;AAOF;EACE;EACA;;;AAKF;EACE;;;AAKF;EACE;;;AAOF;EACE;EACA;;;AAQF;EACE;;;AAQF;EACE;;;AIpkBF;ENmQM,WALI;EM5PR,aHwoB4B;;;AGnoB5B;ENgQM;EM5PJ,aHynBkB;EGxnBlB,aHwmB0B;;AHzgB1B;EMpGF;INuQM;;;;AMvQN;ENgQM;EM5PJ,aHynBkB;EGxnBlB,aHwmB0B;;AHzgB1B;EMpGF;INuQM;;;;AMvQN;ENgQM;EM5PJ,aHynBkB;EGxnBlB,aHwmB0B;;AHzgB1B;EMpGF;INuQM;;;;AMvQN;ENgQM;EM5PJ,aHynBkB;EGxnBlB,aHwmB0B;;AHzgB1B;EMpGF;INuQM;;;;AMvQN;ENgQM;EM5PJ,aHynBkB;EGxnBlB,aHwmB0B;;AHzgB1B;EMpGF;INuQM;;;;AMvQN;ENgQM;EM5PJ,aHynBkB;EGxnBlB,aHwmB0B;;AHzgB1B;EMpGF;INuQM;;;;AM/OR;ECvDE;EACA;;;AD2DF;EC5DE;EACA;;;AD8DF;EACE;;AAEA;EACE,cHkoB0B;;;AGxnB9B;EN8MM,WALI;EMvMR;;;AAIF;EACE,eHiUO;EH1HH,WALI;;AM/LR;EACE;;;AAIJ;EACE;EACA,eHuTO;EH1HH,WALI;EMtLR,OHtFS;;AGwFT;EACE;;;AEhGJ;ECIE;EAGA;;;ADDF;EACE,SLyjDkC;EKxjDlC,kBLyjDkC;EKxjDlC;EHGE;EIRF;EAGA;;;ADcF;EAEE;;;AAGF;EACE;EACA;;;AAGF;ERyPM,WALI;EQlPR,OL4iDkC;;;AO9kDlC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ECHA;EACA;EACA;EACA;EACA;EACA;EACA;;;ACsDE;EF5CE;IACE,WPkee;;;ASvbnB;EF5CE;IACE,WPkee;;;ASvbnB;EF5CE;IACE,WPkee;;;ASvbnB;EF5CE;IACE,WPkee;;;ASvbnB;EF5CE;IACE,WPkee;;;AUlfvB;EAEI;EAAA;EAAA;EAAA;EAAA;EAAA;;;AAKF;ECNA;EACA;EACA;EACA;EAEA;EACA;EACA;;ADEE;ECOF;EACA;EACA;EACA;EACA;EACA;;;AA+CI;EACE;;;AAGF;EApCJ;EACA;;;AAcA;EACE;EACA;;;AAFF;EACE;EACA;;;AAFF;EACE;EACA;;;AAFF;EACE;EACA;;;AAFF;EACE;EACA;;;AAFF;EACE;EACA;;;AA+BE;EAhDJ;EACA;;;AAqDQ;EAhEN;EACA;;;AA+DM;EAhEN;EACA;;;AA+DM;EAhEN;EACA;;;AA+DM;EAhEN;EACA;;;AA+DM;EAhEN;EACA;;;AA+DM;EAhEN;EACA;;;AA+DM;EAhEN;EACA;;;AA+DM;EAhEN;EACA;;;AA+DM;EAhEN;EACA;;;AA+DM;EAhEN;EACA;;;AA+DM;EAhEN;EACA;;;AA+DM;EAhEN;EACA;;;AAuEQ;EAxDV;;;AAwDU;EAxDV;;;AAwDU;EAxDV;;;AAwDU;EAxDV;;;AAwDU;EAxDV;;;AAwDU;EAxDV;;;AAwDU;EAxDV;;;AAwDU;EAxDV;;;AAwDU;EAxDV;;;AAwDU;EAxDV;;;AAwDU;EAxDV;;;AAmEM;AAAA;EAEE;;;AAGF;AAAA;EAEE;;;AAPF;AAAA;EAEE;;;AAGF;AAAA;EAEE;;;AAPF;AAAA;EAEE;;;AAGF;AAAA;EAEE;;;AAPF;AAAA;EAEE;;;AAGF;AAAA;EAEE;;;AAPF;AAAA;EAEE;;;AAGF;AAAA;EAEE;;;AAPF;AAAA;EAEE;;;AAGF;AAAA;EAEE;;;AF1DN;EEUE;IACE;;EAGF;IApCJ;IACA;;EAcA;IACE;IACA;;EAFF;IACE;IACA;;EAFF;IACE;IACA;;EAFF;IACE;IACA;;EAFF;IACE;IACA;;EAFF;IACE;IACA;;EA+BE;IAhDJ;IACA;;EAqDQ;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EAuEQ;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAmEM;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;;AF1DN;EEUE;IACE;;EAGF;IApCJ;IACA;;EAcA;IACE;IACA;;EAFF;IACE;IACA;;EAFF;IACE;IACA;;EAFF;IACE;IACA;;EAFF;IACE;IACA;;EAFF;IACE;IACA;;EA+BE;IAhDJ;IACA;;EAqDQ;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EAuEQ;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAmEM;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;;AF1DN;EEUE;IACE;;EAGF;IApCJ;IACA;;EAcA;IACE;IACA;;EAFF;IACE;IACA;;EAFF;IACE;IACA;;EAFF;IACE;IACA;;EAFF;IACE;IACA;;EAFF;IACE;IACA;;EA+BE;IAhDJ;IACA;;EAqDQ;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EAuEQ;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAmEM;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;;AF1DN;EEUE;IACE;;EAGF;IApCJ;IACA;;EAcA;IACE;IACA;;EAFF;IACE;IACA;;EAFF;IACE;IACA;;EAFF;IACE;IACA;;EAFF;IACE;IACA;;EAFF;IACE;IACA;;EA+BE;IAhDJ;IACA;;EAqDQ;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EAuEQ;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAmEM;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;;AF1DN;EEUE;IACE;;EAGF;IApCJ;IACA;;EAcA;IACE;IACA;;EAFF;IACE;IACA;;EAFF;IACE;IACA;;EAFF;IACE;IACA;;EAFF;IACE;IACA;;EAFF;IACE;IACA;;EA+BE;IAhDJ;IACA;;EAqDQ;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EA+DM;IAhEN;IACA;;EAuEQ;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAwDU;IAxDV;;EAmEM;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;EAPF;AAAA;IAEE;;EAGF;AAAA;IAEE;;;ACrHV;EAEE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA,eZkYO;EYjYP,gBZksB4B;EYjsB5B;;AAOA;EACE;EAEA;EACA;EACA,qBZ0sB0B;EYzsB1B;;AAGF;EACE;;AAGF;EACE;;;AAIJ;EACE;;;AAOF;EACE;;;AAUA;EACE;;;AAeF;EACE;;AAGA;EACE;;;AAOJ;EACE;;AAGF;EACE;;;AAUF;EACE;EACA;;;AAMF;EACE;EACA;;;AAQJ;EACE;EACA;;;AAQA;EACE;EACA;;;AC5IF;EAOE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;;;AAlBF;EAOE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;;;AAlBF;EAOE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;;;AAlBF;EAOE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;;;AAlBF;EAOE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;;;AAlBF;EAOE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;;;AAlBF;EAOE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;;;AAlBF;EAOE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;;;ADiJA;EACE;EACA;;;AH3FF;EGyFA;IACE;IACA;;;AH3FF;EGyFA;IACE;IACA;;;AH3FF;EGyFA;IACE;IACA;;;AH3FF;EGyFA;IACE;IACA;;;AH3FF;EGyFA;IACE;IACA;;;AEnKN;EACE,edi2BsC;;;Acx1BxC;EACE;EACA;EACA;EjB8QI,WALI;EiBrQR,ad+lB4B;;;Ac3lB9B;EACE;EACA;EjBoQI,WALI;;;AiB3PV;EACE;EACA;EjB8PI,WALI;;;AkBtRV;EACE,Yfy1BsC;EH/jBlC,WALI;EkBjRR,Ofy1BsC;;;AgB91BxC;EACE;EACA;EACA;EnBwRI,WALI;EmBhRR,ahBkmB4B;EgBjmB5B,ahBymB4B;EgBxmB5B,OhBs3BsC;EgBr3BtC,kBfIe;EeHf;EACA;EACA;EdGE;EeHE,YDMJ;;ACFI;EDhBN;ICiBQ;;;ADGN;EACE;;AAEA;EACE;;AAKJ;EACE,OhBg2BoC;EgB/1BpC,kBflBa;EemBb,chBw2BoC;EgBv2BpC;EAKE,YhBkhBkB;;AgB9gBtB;EAME;EAMA;EAKA;;AAKF;EACE;EACA;;AAIF;EACE,OhBs0BoC;EgBp0BpC;;AAQF;EAEE,kBhBwyBoC;EgBryBpC;;AAIF;EACE;EACA;EACA,mBfpEkB;EeqElB,OhBgyBoC;EkB93BtC,kBlB+hCgC;EgB/7B9B;EACA;EACA;EACA;EACA,yBf9EiB;Ee+EjB;ECzFE,YD0FF;;ACtFE;ED0EJ;ICzEM;;;ADwFN;EACE,kBhBs7B8B;;;AgB76BlC;EACE;EACA;EACA;EACA;EACA,ahBwf4B;EgBvf5B,OhBqxBsC;EgBpxBtC;EACA;EACA;;AAEA;EACE;;AAGF;EAEE;EACA;;;AAWJ;EACE,YhBswBsC;EgBrwBtC;EnByII,WALI;EKvQN;;AcuIF;EACE;EACA;EACA,mBhB+nB0B;;;AgB3nB9B;EACE,YhB0vBsC;EgBzvBtC;EnB4HI,WALI;EKvQN;;AcoJF;EACE;EACA;EACA,mBhBsnB0B;;;AgB9mB5B;EACE,YhBuuBoC;;AgBpuBtC;EACE,YhBouBoC;;AgBjuBtC;EACE,YhBiuBoC;;;AgB5tBxC;EACE,OhB+tBsC;EgB9tBtC,QhBwtBsC;EgBvtBtC,SfvKoB;;AeyKpB;EACE;;AAGF;EACE;EdvLA;;Ac2LF;EACE;Ed5LA;;AcgMF;EAAoB,QhBwsBkB;;AgBvsBtC;EAAoB,QhBwsBkB;;;AmBv5BxC;EACE;EAEA;EACA;EACA;EtBqRI,WALI;EsB7QR,anB+lB4B;EmB9lB5B,anBsmB4B;EmBrmB5B,OnBm3BsC;EmBl3BtC,kBlBCe;EkBAf;EACA;EACA,qBnB09BkC;EmBz9BlC,iBnB09BkC;EmBz9BlC;EjBFE;EeHE,YEQJ;EACA;;AFLI;EEfN;IFgBQ;;;AEMN;EACE,cnBg3BoC;EmB/2BpC;EAKE,YnB29B4B;;AmBv9BhC;EAEE,elBXkB;EkBYlB;;AAGF;EAEE,kBnBi1BoC;;AmB50BtC;EACE;EACA;;;AAIJ;EACE,anBiuB4B;EmBhuB5B,gBnBguB4B;EmB/tB5B,cnBguB4B;EH7fxB,WALI;EKvQN;;;AiB8CJ;EACE,anB6tB4B;EmB5tB5B,gBnB4tB4B;EmB3tB5B,cnB4tB4B;EHjgBxB,WALI;EKvQN;;;AiBwDA;EACE;;;ACxEN;EACE;EACA,YpB+5BwC;EoB95BxC,cpB+5BwC;EoB95BxC,epB+5BwC;;AoB75BxC;EACE;EACA;;;AAIJ;EACE,epBq5BwC;EoBp5BxC;EACA;;AAEA;EACE;EACA;EACA;;;AAIJ;EACE;EAEA,OpBq4BwC;EoBp4BxC,QpBo4BwC;EoBn4BxC;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QpBu4BwC;EoBt4BxC;EACA;;AAGA;ElB1BE;;AkB8BF;EAEE,epB83BsC;;AoB33BxC;EACE,QpBq3BsC;;AoBl3BxC;EACE,cpBi1BoC;EoBh1BpC;EACA,YpB+foB;;AoB5ftB;EACE,kBnB/DM;EmBgEN,cnBhEM;;AmBkEN;EAII;;AAIJ;EAII;;AAKN;EACE,kBnBpFM;EmBqFN,cnBrFM;EmB0FJ;;AAIJ;EACE;EACA;EACA,SpB61BuC;;AoBt1BvC;EACE;EACA,SpBo1BqC;;;AoBt0B3C;EACE,cpB+0BgC;;AoB70BhC;EACE;EAEA,OpBy0B8B;EoBx0B9B;EACA;EACA;ElBhHA;EeHE,YGqHF;;AHjHE;EGyGJ;IHxGM;;;AGkHJ;EACE;;AAGF;EACE,qBpBw0B4B;EoBn0B1B;;AAKN;EACE,epBmzB8B;EoBlzB9B;;AAEA;EACE;EACA;;;AAKN;EACE;EACA,cpBiyBgC;;;AoB9xBlC;EACE;EACA;EACA;;AAIE;EACE;EACA;EACA,SpBkpBwB;;;AoB3oB1B;EACE;;;AClLN;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAIA;EAA0B,YrBwgCa;;AqBvgCvC;EAA0B,YrBugCa;;AqBpgCzC;EACE;;AAGF;EACE,OrBy/BuC;EqBx/BvC,QrBw/BuC;EqBv/BvC;EHzBF,kBjBFQ;EoB6BN,QrBw/BuC;EEpgCvC;EeHE,YIkBF;EACA;;AJfE;EIMJ;IJLM;;;AIgBJ;EHjCF,kBlBwhCyC;;AqBl/BzC;EACE,OrBk+B8B;EqBj+B9B,QrBk+B8B;EqBj+B9B;EACA,QrBi+B8B;EqBh+B9B,kBrBi+B8B;EqBh+B9B;EnB7BA;;AmBkCF;EACE,OrB89BuC;EqB79BvC,QrB69BuC;EkBhhCzC,kBjBFQ;EoBuDN,QrB89BuC;EEpgCvC;EeHE,YI4CF;EACA;;AJzCE;EIiCJ;IJhCM;;;AI0CJ;EH3DF,kBlBwhCyC;;AqBx9BzC;EACE,OrBw8B8B;EqBv8B9B,QrBw8B8B;EqBv8B9B;EACA,QrBu8B8B;EqBt8B9B,kBrBu8B8B;EqBt8B9B;EnBvDA;;AmB4DF;EACE;;AAEA;EACE,kBrB08BqC;;AqBv8BvC;EACE,kBrBs8BqC;;;AsB7hC3C;EACE;;AAEA;AAAA;AAAA;EAGE,QtBkiCoC;EsBjiCpC,YtBiiCoC;EsBhiCpC,atBiiCoC;;AsB9hCtC;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;ELRE,YKSF;;ALLE;EKTJ;ILUM;;;AKON;AAAA;EAEE;;AAEA;AAAA;EACE;;AAGF;AAAA;AAAA;EAEE,atBsgCkC;EsBrgClC,gBtBsgCkC;;AsBngCpC;AAAA;EACE,atBigCkC;EsBhgClC,gBtBigCkC;;AsB7/BtC;EACE,atB2/BoC;EsB1/BpC,gBtB2/BoC;;AsBp/BpC;AAAA;AAAA;AAAA;EACE;EACA,WtBq/BkC;;AsBn/BlC;AAAA;AAAA;AAAA;EACE;EACA;EACA;EACA,QtB6+BgC;EsB5+BhC;EACA,kBrBlDS;ECEb;;AoBuDA;EACE;EACA,WtBo+BkC;;AsB/9BpC;EACE;;AAIJ;EACE,OtBzEO;;AsB2EP;EACE,kBtBqyBkC;;;AuB33BxC;EACE;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;EAGE;EACA;EACA;EACA;;AAIF;AAAA;AAAA;EAGE;;AAMF;EACE;EACA;;AAEA;EACE;;;AAWN;EACE;EACA;EACA;E1B8OI,WALI;E0BvOR,avByjB4B;EuBxjB5B,avBgkB4B;EuB/jB5B,OvB60BsC;EuB50BtC;EACA;EACA,kBvBo6BsC;EuBn6BtC;ErBtCE;;;AqBgDJ;AAAA;AAAA;AAAA;EAIE;E1BwNI,WALI;EKvQN;;;AqByDJ;AAAA;AAAA;AAAA;EAIE;E1B+MI,WALI;EKvQN;;;AqBkEJ;AAAA;EAEE;;;AAaE;AAAA;AAAA;AAAA;ErBjEA;EACA;;AqByEA;AAAA;AAAA;AAAA;ErB1EA;EACA;;AqBsFF;EACE;ErB1EA;EACA;;AqB6EF;AAAA;ErB9EE;EACA;;;AsBxBF;EACE;EACA;EACA,YxBi0BoC;EH/jBlC,WALI;E2B1PN,OxB4iCqB;;;AwBziCvB;EACE;EACA;EACA;EACA;EACA;EACA;EACA;E3BqPE,WALI;E2B7ON,OxB+hCqB;EwB9hCrB,kBxB8hCqB;EEzjCrB;;;AsBgCA;AAAA;AAAA;AAAA;EAEE;;;AA/CF;EAqDE,cxBihCmB;EwB9gCjB,exBw1BgC;EwBv1BhC;EACA;EACA;EACA;;AAGF;EACE,cxBsgCiB;EwBrgCjB,YxBqgCiB;;;AwBtkCrB;EA0EI,exBs0BgC;EwBr0BhC;;;AA3EJ;EAkFE,cxBo/BmB;;AwBj/BjB;EAEE;EACA,exBo5B8B;EwBn5B9B;EACA;;AAIJ;EACE,cxBu+BiB;EwBt+BjB,YxBs+BiB;;;AwBtkCrB;EAwGI;;;AAxGJ;EA+GE,cxBu9BmB;;AwBr9BnB;EACE,kBxBo9BiB;;AwBj9BnB;EACE,YxBg9BiB;;AwB78BnB;EACE,OxB48BiB;;;AwBv8BrB;EACE;;;AAhIF;AAAA;AAAA;AAAA;AAAA;EA0IM;;;AAtHR;EACE;EACA;EACA,YxBi0BoC;EH/jBlC,WALI;E2B1PN,OxB4iCqB;;;AwBziCvB;EACE;EACA;EACA;EACA;EACA;EACA;EACA;E3BqPE,WALI;E2B7ON,OxB+hCqB;EwB9hCrB,kBxB8hCqB;EEzjCrB;;;AsBgCA;AAAA;AAAA;AAAA;EAEE;;;AA/CF;EAqDE,cxBihCmB;EwB9gCjB,exBw1BgC;EwBv1BhC;EACA;EACA;EACA;;AAGF;EACE,cxBsgCiB;EwBrgCjB,YxBqgCiB;;;AwBtkCrB;EA0EI,exBs0BgC;EwBr0BhC;;;AA3EJ;EAkFE,cxBo/BmB;;AwBj/BjB;EAEE;EACA,exBo5B8B;EwBn5B9B;EACA;;AAIJ;EACE,cxBu+BiB;EwBt+BjB,YxBs+BiB;;;AwBtkCrB;EAwGI;;;AAxGJ;EA+GE,cxBu9BmB;;AwBr9BnB;EACE,kBxBo9BiB;;AwBj9BnB;EACE,YxBg9BiB;;AwB78BnB;EACE,OxB48BiB;;;AwBv8BrB;EACE;;;AAhIF;AAAA;AAAA;AAAA;AAAA;EA4IM;;;AC9IV;EAEE;EACA;EACA;E5BuRI,oBALI;E4BhRR;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;E5BsQI,WALI;E4B/PR;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EvBjBE;EgBfF,kBOkCqB;ERtBjB,YQwBJ;;ARpBI;EQhBN;IRiBQ;;;AQqBN;EACE;EAEA;EACA;;AAGF;EAEE;EACA;EACA;;AAGF;EACE;EPrDF,kBOsDuB;EACrB;EACA;EAKE;;AAIJ;EACE;EACA;EAKE;;AAIJ;EAKE;EACA;EAGA;;AAGA;EAKI;;AAKN;EAGE;EACA;EACA;EAEA;EACA;;;AAYF;ECtGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;ADyFA;ECtGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;ADyFA;ECtGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;ADyFA;ECtGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;ADyFA;ECtGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;ADyFA;ECtGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;ADyFA;ECtGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;ADyFA;ECtGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;ADmHA;ECvGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AD0FA;ECvGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AD0FA;ECvGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AD0FA;ECvGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AD0FA;ECvGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AD0FA;ECvGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AD0FA;ECvGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AD0FA;ECvGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;ADsGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA,iBxBxJgB;;AwBkKhB;EACE;;AAGF;EACE;;;AAWJ;ECxIE;EACA;E7B8NI,oBALI;E6BvNR;;;ADyIF;EC5IE;EACA;E7B8NI,oBALI;E6BvNR;;;ACnEF;EVgBM,YUfJ;;AVmBI;EUpBN;IVqBQ;;;AUlBN;EACE;;;AAMF;EACE;;;AAIJ;EACE;EACA;EVDI,YUEJ;;AVEI;EULN;IVMQ;;;AUDN;EACE;EACA;EVNE,YUOF;;AVHE;EUAJ;IVCM;;;;AWpBR;AAAA;AAAA;AAAA;AAAA;AAAA;EAME;;;AAGF;EACE;;ACwBE;EACE;EACA,a7B6hBwB;E6B5hBxB,gB7B2hBwB;E6B1hBxB;EArCJ;EACA;EACA;EACA;;AA0DE;EACE;;;AD9CN;EAEE;EACA;EACA;EACA;EACA;E/BuQI,yBALI;E+BhQR;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EACA;EACA;E/B0OI,WALI;E+BnOR;EACA;EACA;EACA;EACA;EACA;E1BzCE;;A0B6CF;EACE;EACA;EACA;;;AAwBA;EACE;;AAEA;EACE;EACA;;;AAIJ;EACE;;AAEA;EACE;EACA;;;AnB1CJ;EmB4BA;IACE;;EAEA;IACE;IACA;;EAIJ;IACE;;EAEA;IACE;IACA;;;AnB1CJ;EmB4BA;IACE;;EAEA;IACE;IACA;;EAIJ;IACE;;EAEA;IACE;IACA;;;AnB1CJ;EmB4BA;IACE;;EAEA;IACE;IACA;;EAIJ;IACE;;EAEA;IACE;IACA;;;AnB1CJ;EmB4BA;IACE;;EAEA;IACE;IACA;;EAIJ;IACE;;EAEA;IACE;IACA;;;AnB1CJ;EmB4BA;IACE;;EAEA;IACE;IACA;;EAIJ;IACE;;EAEA;IACE;IACA;;;AAUN;EACE;EACA;EACA;EACA;;ACpFA;EACE;EACA,a7B6hBwB;E6B5hBxB,gB7B2hBwB;E6B1hBxB;EA9BJ;EACA;EACA;EACA;;AAmDE;EACE;;;ADgEJ;EACE;EACA;EACA;EACA;EACA;;AClGA;EACE;EACA,a7B6hBwB;E6B5hBxB,gB7B2hBwB;E6B1hBxB;EAvBJ;EACA;EACA;EACA;;AA4CE;EACE;;AD0EF;EACE;;;AAMJ;EACE;EACA;EACA;EACA;EACA;;ACnHA;EACE;EACA,a7B6hBwB;E6B5hBxB,gB7B2hBwB;E6B1hBxB;;AAWA;EACE;;AAGF;EACE;EACA,c7B0gBsB;E6BzgBtB,gB7BwgBsB;E6BvgBtB;EAnCN;EACA;EACA;;AAsCE;EACE;;AD2FF;EACE;;;AAON;EACE;EACA;EACA;EACA;EACA;;;AAMF;EACE;EACA;EACA;EACA;EACA,a5Byb4B;E4Bxb5B;EACA;EAEA;EACA;EACA;E1BtKE;;A0ByKF;EAEE;EV1LF,kBU4LuB;;AAGvB;EAEE;EACA;EVlMF,kBUmMuB;;AAGvB;EAEE;EACA;EACA;;;AAMJ;EACE;;;AAIF;EACE;EACA;EACA;E/BmEI,WALI;E+B5DR;EACA;;;AAIF;EACE;EACA;EACA;;;AAIF;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AEtPF;AAAA;EAEE;EACA;EACA;;AAEA;AAAA;EACE;EACA;;AAKF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAME;;;AAKJ;EACE;EACA;EACA;;AAEA;EACE;;;AAIJ;E5BhBI;;A4BoBF;AAAA;EAEE;;AAIF;AAAA;AAAA;E5BVE;EACA;;A4BmBF;AAAA;AAAA;E5BNE;EACA;;;A4BwBJ;EACE;EACA;;AAEA;EAGE;;AAGF;EACE;;;AAIJ;EACE;EACA;;;AAGF;EACE;EACA;;;AAoBF;EACE;EACA;EACA;;AAEA;AAAA;EAEE;;AAGF;AAAA;EAEE;;AAIF;AAAA;E5B1FE;EACA;;A4B8FF;AAAA;E5B7GE;EACA;;;A6BxBJ;EAEE;EACA;EAEA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;ElCsQI,WALI;EkC/PR;EACA;EAEA;EACA;EdfI,YcgBJ;;AdZI;EcGN;IdFQ;;;AcaN;EAEE;;AAIF;EACE;EACA,Y/BkhBoB;;A+B9gBtB;EACE;EACA;EACA;;;AAQJ;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;;AAEA;EACE;EACA;E7B5CA;EACA;;A6B8CA;EAGE;EACA;;AAGF;EAEE;EACA;EACA;;AAIJ;AAAA;EAEE;EACA;EACA;;AAGF;EAEE;E7BvEA;EACA;;;A6BiFJ;EAEE;EACA;EACA;;AAGA;E7BlGE;;A6BqGA;EACE;EACA;EACA;;AAIJ;AAAA;EAEE;Eb7HF,kBa8HuB;;;AASzB;EAEE;EACA;EACA;EAGA;;AAEA;EACE;EACA;EACA;;AAEA;EAEE;;AAIJ;AAAA;EAEE,a/B8c0B;E+B7c1B;EACA;;;AAUF;AAAA;EAEE;EACA;;;AAKF;AAAA;EAEE;EACA;EACA;;;AAMF;AAAA;EACE;;;AAUF;EACE;;AAEF;EACE;;;ACzMJ;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EACA;EACA;;AAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACE;EACA;EACA;EACA;;AAoBJ;EACE;EACA;EACA;EnC4NI,WALI;EmCrNR;EAEA;;AAEA;EAEE;;;AAUJ;EAEE;EACA;EAEA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EACA;;AAGE;EAEE;;AAIJ;EACE;;;AASJ;EACE,ahCwgCkC;EgCvgClC,gBhCugCkC;EgCtgClC;;AAEA;AAAA;AAAA;EAGE;;;AAaJ;EACE;EACA;EAGA;;;AAIF;EACE;EnCyII,WALI;EmClIR;EACA;EACA;EACA;E9BxIE;EeHE,Ye6IJ;;AfzII;EeiIN;IfhIQ;;;Ae0IN;EACE;;AAGF;EACE;EACA;EACA;;;AAMJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AvB1HE;EuBsIA;IAEI;IACA;;EAEA;IACE;;EAEA;IACE;;EAGF;IACE;IACA;;EAIJ;IACE;;EAGF;IACE;IACA;;EAGF;IACE;;EAGF;IAEE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;If9NJ,YegOI;;EAGA;IACE;;EAGF;IACE;IACA;IACA;IACA;;;AvB5LR;EuBsIA;IAEI;IACA;;EAEA;IACE;;EAEA;IACE;;EAGF;IACE;IACA;;EAIJ;IACE;;EAGF;IACE;IACA;;EAGF;IACE;;EAGF;IAEE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;If9NJ,YegOI;;EAGA;IACE;;EAGF;IACE;IACA;IACA;IACA;;;AvB5LR;EuBsIA;IAEI;IACA;;EAEA;IACE;;EAEA;IACE;;EAGF;IACE;IACA;;EAIJ;IACE;;EAGF;IACE;IACA;;EAGF;IACE;;EAGF;IAEE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;If9NJ,YegOI;;EAGA;IACE;;EAGF;IACE;IACA;IACA;IACA;;;AvB5LR;EuBsIA;IAEI;IACA;;EAEA;IACE;;EAEA;IACE;;EAGF;IACE;IACA;;EAIJ;IACE;;EAGF;IACE;IACA;;EAGF;IACE;;EAGF;IAEE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;If9NJ,YegOI;;EAGA;IACE;;EAGF;IACE;IACA;IACA;IACA;;;AvB5LR;EuBsIA;IAEI;IACA;;EAEA;IACE;;EAEA;IACE;;EAGF;IACE;IACA;;EAIJ;IACE;;EAGF;IACE;IACA;;EAGF;IACE;;EAGF;IAEE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;If9NJ,YegOI;;EAGA;IACE;;EAGF;IACE;IACA;IACA;IACA;;;AAtDR;EAEI;EACA;;AAEA;EACE;;AAEA;EACE;;AAGF;EACE;EACA;;AAIJ;EACE;;AAGF;EACE;EACA;;AAGF;EACE;;AAGF;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;Ef9NJ,YegOI;;AAGA;EACE;;AAGF;EACE;EACA;EACA;EACA;;;AAiBZ;AAAA;EAGE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAME;EACE;;;ACzRN;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;E/BjBE;;A+BqBF;EACE;EACA;;AAGF;EACE;EACA;;AAEA;EACE;E/BtBF;EACA;;A+ByBA;EACE;E/BbF;EACA;;A+BmBF;AAAA;EAEE;;;AAIJ;EAGE;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;;;AAQA;EACE;;;AAQJ;EACE;EACA;EACA;EACA;EACA;;AAEA;E/B7FE;;;A+BkGJ;EACE;EACA;EACA;EACA;;AAEA;E/BxGE;;;A+BkHJ;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;;;AAIJ;EACE;EACA;;;AAIF;EACE;EACA;EACA;EACA;EACA;EACA;E/B1IE;;;A+B8IJ;AAAA;AAAA;EAGE;;;AAGF;AAAA;E/B3II;EACA;;;A+B+IJ;AAAA;E/BlII;EACA;;;A+B8IF;EACE;;AxB3HA;EwBuHJ;IAQI;IACA;;EAGA;IAEE;IACA;;EAEA;IACE;IACA;;EAKA;I/B3KJ;IACA;;E+B6KM;AAAA;IAGE;;EAEF;AAAA;IAGE;;EAIJ;I/B5KJ;IACA;;E+B8KM;AAAA;IAGE;;EAEF;AAAA;IAGE;;;;ACpOZ;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIF;EACE;EACA;EACA;EACA;EACA;ErC2PI,WALI;EqCpPR;EACA;EACA;EACA;EhCtBE;EgCwBF;EjB3BI,YiB4BJ;;AjBxBI;EiBWN;IjBVQ;;;AiByBN;EACE;EACA;EACA;;AAEA;EACE;EACA;;AAKJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EjBlDE,YiBmDF;;AjB/CE;EiBsCJ;IjBrCM;;;AiBiDN;EACE;;AAGF;EACE;EACA;EACA;EACA;;;AAIJ;EACE;;;AAGF;EACE;EACA;EACA;;AAEA;EhC/DE;EACA;;AgCiEA;EhClEA;EACA;;AgCsEF;EACE;;AAIF;EhC9DE;EACA;;AgCiEE;EhClEF;EACA;;AgCsEA;EhCvEA;EACA;;;AgC4EJ;EACE;;;AASA;EACE;;AAGF;EACE;EACA;EhCpHA;;AgCuHA;EAAgB;;AAChB;EAAe;;AAGb;EhC3HF;;;AgCqIA;EACE;EACA;;;AC1JN;EAEE;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EtC+QI,WALI;EsCxQR;EACA;EjCAE;;;AiCMF;EACE;;AAEA;EACE;EACA;EACA;EACA;;AAIJ;EACE;;;ACrCJ;EAEE;EACA;EvC4RI,2BALI;EuCrRR;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EhCpBA;EACA;;;AgCuBF;EACE;EACA;EACA;EvCgQI,WALI;EuCzPR;EAEA;EACA;EnBpBI,YmBqBJ;;AnBjBI;EmBQN;InBPQ;;;AmBkBN;EACE;EACA;EAEA;EACA;;AAGF;EACE;EACA;EACA;EACA,SpCouCgC;EoCnuChC;;AAGF;EAEE;EACA;ElBtDF,kBkBuDuB;EACrB;;AAGF;EAEE;EACA;EACA;EACA;;;AAKF;EACE,apCusCgC;;AoClsC9B;ElC9BF;EACA;;AkCmCE;ElClDF;EACA;;;AkCkEJ;EClGE;EACA;ExC0RI,2BALI;EwCnRR;;;ADmGF;ECtGE;EACA;ExC0RI,2BALI;EwCnRR;;;ACFF;EAEE;EACA;EzCuRI,sBALI;EyChRR;EACA;EACA;EAGA;EACA;EzC+QI,WALI;EyCxQR;EACA;EACA;EACA;EACA;EACA;EpCJE;;AoCSF;EACE;;;AAKJ;EACE;EACA;;;AChCF;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EACA;EACA;ErCHE;;;AqCQJ;EAEE;;;AAIF;EACE,avC6kB4B;EuC5kB5B;;;AAQF;EACE,evCg+C8B;;AuC79C9B;EACE;EACA;EACA;EACA;EACA;;;AAQF;EACE;EACA;EACA;EACA;;;AAJF;EACE;EACA;EACA;EACA;;;AAJF;EACE;EACA;EACA;EACA;;;AAJF;EACE;EACA;EACA;EACA;;;AAJF;EACE;EACA;EACA;EACA;;;AAJF;EACE;EACA;EACA;EACA;;;AAJF;EACE;EACA;EACA;EACA;;;AAJF;EACE;EACA;EACA;EACA;;;AC5DF;EACE;IAAK,uBxCmhD2B;;;AwC9gDpC;AAAA;EAGE;E3CkRI,yBALI;E2C3QR;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;E3CsQI,WALI;E2C/PR;EtCRE;;;AsCaJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EvBxBI,YuByBJ;;AvBrBI;EuBYN;IvBXQ;;;;AuBuBR;EtBAE;EsBEA;;;AAGF;EACE;;;AAGF;EACE;;;AAIA;EACE;;AAGE;EAJJ;IAKM;;;;AC3DR;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EAGA;EACA;EvCXE;;;AuCeJ;EACE;EACA;;AAEA;EAEE;EACA;;;AASJ;EACE;EACA;EACA;;AAGA;EAEE;EACA;EACA;EACA;;AAGF;EACE;EACA;;;AAQJ;EACE;EACA;EACA;EACA;EAEA;EACA;;AAEA;EvCvDE;EACA;;AuC0DF;EvC7CE;EACA;;AuCgDF;EAEE;EACA;EACA;;AAIF;EACE;EACA;EACA;EACA;;AAIF;EACE;;AAEA;EACE;EACA;;;AAaF;EACE;;AAGE;EvCvDJ;EAZA;;AuCwEI;EvCxEJ;EAYA;;AuCiEI;EACE;;AAGF;EACE;EACA;;AAEA;EACE;EACA;;;AhCtFR;EgC8DA;IACE;;EAGE;IvCvDJ;IAZA;;EuCwEI;IvCxEJ;IAYA;;EuCiEI;IACE;;EAGF;IACE;IACA;;EAEA;IACE;IACA;;;AhCtFR;EgC8DA;IACE;;EAGE;IvCvDJ;IAZA;;EuCwEI;IvCxEJ;IAYA;;EuCiEI;IACE;;EAGF;IACE;IACA;;EAEA;IACE;IACA;;;AhCtFR;EgC8DA;IACE;;EAGE;IvCvDJ;IAZA;;EuCwEI;IvCxEJ;IAYA;;EuCiEI;IACE;;EAGF;IACE;IACA;;EAEA;IACE;IACA;;;AhCtFR;EgC8DA;IACE;;EAGE;IvCvDJ;IAZA;;EuCwEI;IvCxEJ;IAYA;;EuCiEI;IACE;;EAGF;IACE;IACA;;EAEA;IACE;IACA;;;AhCtFR;EgC8DA;IACE;;EAGE;IvCvDJ;IAZA;;EuCwEI;IvCxEJ;IAYA;;EuCiEI;IACE;;EAGF;IACE;IACA;;EAEA;IACE;IACA;;;AAcZ;EvChJI;;AuCmJF;EACE;;AAEA;EACE;;;AAaJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAVF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAVF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAVF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAVF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAVF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAVF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAVF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AC5LJ;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA,O1C+oD2B;E0C9oD3B,Q1C8oD2B;E0C7oD3B;EACA;EACA;EACA;ExCJE;EwCMF;;AAGA;EACE;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAGF;EAEE;EACA;EACA;;;AAQJ;EAHE;;;AASE;EATF;;;ACjDF;EAEE;EACA;EACA;EACA;EACA;E9CyRI,sBALI;E8ClRR;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;E9C2QI,WALI;E8CpQR;EACA;EACA;EACA;EACA;EACA;EzCRE;;AyCWF;EACE;;AAGF;EACE;;;AAIJ;EACE;EAEA;EACA;EACA;EACA;EACA;;AAEA;EACE;;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EzChCE;EACA;;AyCkCF;EACE;EACA;;;AAIJ;EACE;EACA;;;AC9DF;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;;;AAOF;EACE;EACA;EACA;EAEA;;AAGA;E3B5CI,Y2B6CF;EACA,W5Cy7CgC;;AiBn+C9B;E2BwCJ;I3BvCM;;;A2B2CN;EACE,W5Cu7CgC;;A4Cn7ClC;EACE,W5Co7CgC;;;A4Ch7CpC;EACE;;AAEA;EACE;EACA;;AAGF;EACE;;;AAIJ;EACE;EACA;EACA;;;AAIF;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;E1CrFE;E0CyFF;;;AAIF;EAEE;EACA;EACA;EClHA;EACA;EACA;EACA,SDkH0B;ECjH1B;EACA;EACA,kBD+G4D;;AC5G5D;EAAS;;AACT;EAAS,SD2GiF;;;AAK5F;EACE;EACA;EACA;EACA;EACA;EACA;E1CtGE;EACA;;A0CwGF;EACE;EACA;;;AAKJ;EACE;EACA;;;AAKF;EACE;EAGA;EACA;;;AAIF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;E1C1HE;EACA;;A0C+HF;EACE;;;AnC5GA;EmCkHF;IACE;IACA;;EAIF;IACE;IACA;IACA;;EAGF;IACE;;;AnC/HA;EmCoIF;AAAA;IAEE;;;AnCtIA;EmC2IF;IACE;;;AAUA;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;E1C1MJ;;A0C8ME;AAAA;E1C9MF;;A0CmNE;EACE;;;AnC3JJ;EmCyIA;IACE;IACA;IACA;IACA;;EAEA;IACE;IACA;I1C1MJ;;E0C8ME;AAAA;I1C9MF;;E0CmNE;IACE;;;AnC3JJ;EmCyIA;IACE;IACA;IACA;IACA;;EAEA;IACE;IACA;I1C1MJ;;E0C8ME;AAAA;I1C9MF;;E0CmNE;IACE;;;AnC3JJ;EmCyIA;IACE;IACA;IACA;IACA;;EAEA;IACE;IACA;I1C1MJ;;E0C8ME;AAAA;I1C9MF;;E0CmNE;IACE;;;AnC3JJ;EmCyIA;IACE;IACA;IACA;IACA;;EAEA;IACE;IACA;I1C1MJ;;E0C8ME;AAAA;I1C9MF;;E0CmNE;IACE;;;AnC3JJ;EmCyIA;IACE;IACA;IACA;IACA;;EAEA;IACE;IACA;I1C1MJ;;E0C8ME;AAAA;I1C9MF;;E0CmNE;IACE;;;AEtOR;EAEE;EACA;EACA;EACA;EACA;EjDwRI,wBALI;EiDjRR;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EClBA,a/C+lB4B;E+C7lB5B;EACA,a/CwmB4B;E+CvmB5B,a/C+mB4B;E+C9mB5B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;ElDgRI,WALI;EiDhQR;EACA;;AAEA;EAAS;;AAET;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;;;AAKN;EACE;;AAEA;EACE;EACA;EACA;;;AAIJ;AACA;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;;;AAIJ;AAEA;EACE;;AAEA;EACE;EACA;EACA;;;AAIJ;AACA;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;;;AAIJ;AAkBA;EACE;EACA;EACA;EACA;EACA;E5CjGE;;;A8CnBJ;EAEE;EACA;EnD4RI,wBALI;EmDrRR;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EnDmRI,+BALI;EmD5QR;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EDzBA,a/C+lB4B;E+C7lB5B;EACA,a/CwmB4B;E+CvmB5B,a/C+mB4B;E+C9mB5B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;ElDgRI,WALI;EmD1PR;EACA;EACA;EACA;E9ChBE;;A8CoBF;EACE;EACA;EACA;;AAEA;EAEE;EACA;EACA;EACA;EACA;EACA;;;AAMJ;EACE;;AAEA;EAEE;;AAGF;EACE;EACA;;AAGF;EACE;EACA;;;AAKN;AAEE;EACE;EACA;EACA;;AAEA;EAEE;;AAGF;EACE;EACA;;AAGF;EACE;EACA;;;AAKN;AAGE;EACE;;AAEA;EAEE;;AAGF;EACE;EACA;;AAGF;EACE;EACA;;AAKJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIJ;AAEE;EACE;EACA;EACA;;AAEA;EAEE;;AAGF;EACE;EACA;;AAGF;EACE;EACA;;;AAKN;AAkBA;EACE;EACA;EnD2GI,WALI;EmDpGR;EACA;EACA;E9C5JE;EACA;;A8C8JF;EACE;;;AAIJ;EACE;EACA;;;ACrLF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;;ACtBA;EACE;EACA;EACA;;;ADuBJ;EACE;EACA;EACA;EACA;EACA;EACA;EhClBI,YgCmBJ;;AhCfI;EgCQN;IhCPQ;;;;AgCiBR;AAAA;AAAA;EAGE;;;AAGF;AAAA;EAEE;;;AAGF;AAAA;EAEE;;;AASA;EACE;EACA;EACA;;AAGF;AAAA;AAAA;EAGE;EACA;;AAGF;AAAA;EAEE;EACA;EhC5DE,YgC6DF;;AhCzDE;EgCqDJ;AAAA;IhCpDM;;;;AgCiER;AAAA;EAEE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA,OjD4gDmC;EiD3gDnC;EACA,OjD1FS;EiD2FT;EACA;EACA;EACA,SjDugDmC;EiB7lD/B,YgCuFJ;;AhCnFI;EgCkEN;AAAA;IhCjEQ;;;AgCqFN;AAAA;AAAA;EAEE,OjDpGO;EiDqGP;EACA;EACA,SjD+/CiC;;;AiD5/CrC;EACE;;;AAGF;EACE;;;AAKF;AAAA;EAEE;EACA,OjDggDmC;EiD//CnC,QjD+/CmC;EiD9/CnC;EACA;EACA;;;AAGF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;EACE;;;AAEF;EACE;;;AAQF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA,cjDw8CmC;EiDv8CnC;EACA,ajDs8CmC;;AiDp8CnC;EACE;EACA;EACA,OjDs8CiC;EiDr8CjC,QjDs8CiC;EiDr8CjC;EACA,cjDs8CiC;EiDr8CjC,ajDq8CiC;EiDp8CjC;EACA;EACA,kBjD1KO;EiD2KP;EACA;EAEA;EACA;EACA,SjD67CiC;EiBrmD/B,YgCyKF;;AhCrKE;EgCoJJ;IhCnJM;;;AgCuKN;EACE,SjD07CiC;;;AiDj7CrC;EACE;EACA;EACA,QjDo7CmC;EiDn7CnC;EACA,ajDi7CmC;EiDh7CnC,gBjDg7CmC;EiD/6CnC,OjDrMS;EiDsMT;;;AAMA;AAAA;EAEE,QjDq7CiC;;AiDl7CnC;EACE,kBjDxMO;;AiD2MT;EACE,OjD5MO;;;AiDkMT;AAAA;AAAA;EAEE,QjDq7CiC;;AiDl7CnC;EACE,kBjDxMO;;AiD2MT;EACE,OjD5MO;;;AmDdX;AAAA;EAEE;EACA;EACA;EACA;EAEA;EACA;;;AAIF;EACE;IAAK;;;AAIP;EAEE;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;;;AAGF;EAEE;EACA;EACA;;;AASF;EACE;IACE;;EAEF;IACE;IACA;;;AAKJ;EAEE;EACA;EACA;EACA;EACA;EAGA;EACA;;;AAGF;EACE;EACA;;;AAIA;EACE;AAAA;IAEE;;;AC/EN;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;A3C6DE;E2C5CF;IAEI;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;InC5BA,YmC8BA;;;AnC1BA;EmCYJ;InCXM;;;ARuDJ;E2C5BE;IACE;IACA;IACA;IACA;IACA;;EAGF;IACE;IACA;IACA;IACA;IACA;;EAGF;IACE;IACA;IACA;IACA;IACA;IACA;IACA;;EAGF;IACE;IACA;IACA;IACA;IACA;IACA;;EAGF;IAEE;;EAGF;IAGE;;;A3C5BJ;E2C/BF;IAiEM;IACA;IACA;;EAEA;IACE;;EAGF;IACE;IACA;IACA;IACA;IAEA;;;;A3CnCN;E2C5CF;IAEI;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;InC5BA,YmC8BA;;;AnC1BA;EmCYJ;InCXM;;;ARuDJ;E2C5BE;IACE;IACA;IACA;IACA;IACA;;EAGF;IACE;IACA;IACA;IACA;IACA;;EAGF;IACE;IACA;IACA;IACA;IACA;IACA;IACA;;EAGF;IACE;IACA;IACA;IACA;IACA;IACA;;EAGF;IAEE;;EAGF;IAGE;;;A3C5BJ;E2C/BF;IAiEM;IACA;IACA;;EAEA;IACE;;EAGF;IACE;IACA;IACA;IACA;IAEA;;;;A3CnCN;E2C5CF;IAEI;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;InC5BA,YmC8BA;;;AnC1BA;EmCYJ;InCXM;;;ARuDJ;E2C5BE;IACE;IACA;IACA;IACA;IACA;;EAGF;IACE;IACA;IACA;IACA;IACA;;EAGF;IACE;IACA;IACA;IACA;IACA;IACA;IACA;;EAGF;IACE;IACA;IACA;IACA;IACA;IACA;;EAGF;IAEE;;EAGF;IAGE;;;A3C5BJ;E2C/BF;IAiEM;IACA;IACA;;EAEA;IACE;;EAGF;IACE;IACA;IACA;IACA;IAEA;;;;A3CnCN;E2C5CF;IAEI;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;InC5BA,YmC8BA;;;AnC1BA;EmCYJ;InCXM;;;ARuDJ;E2C5BE;IACE;IACA;IACA;IACA;IACA;;EAGF;IACE;IACA;IACA;IACA;IACA;;EAGF;IACE;IACA;IACA;IACA;IACA;IACA;IACA;;EAGF;IACE;IACA;IACA;IACA;IACA;IACA;;EAGF;IAEE;;EAGF;IAGE;;;A3C5BJ;E2C/BF;IAiEM;IACA;IACA;;EAEA;IACE;;EAGF;IACE;IACA;IACA;IACA;IAEA;;;;A3CnCN;E2C5CF;IAEI;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;InC5BA,YmC8BA;;;AnC1BA;EmCYJ;InCXM;;;ARuDJ;E2C5BE;IACE;IACA;IACA;IACA;IACA;;EAGF;IACE;IACA;IACA;IACA;IACA;;EAGF;IACE;IACA;IACA;IACA;IACA;IACA;IACA;;EAGF;IACE;IACA;IACA;IACA;IACA;IACA;;EAGF;IAEE;;EAGF;IAGE;;;A3C5BJ;E2C/BF;IAiEM;IACA;IACA;;EAEA;IACE;;EAGF;IACE;IACA;IACA;IACA;IAEA;;;;AA/ER;EAEI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EnC5BA,YmC8BA;;AnC1BA;EmCYJ;InCXM;;;AmC2BF;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EAEE;;AAGF;EAGE;;;AA2BR;EPpHE;EACA;EACA;EACA,S7ComCkC;E6CnmClC;EACA;EACA,kB7CUS;;A6CPT;EAAS;;AACT;EAAS,S7C09CyB;;;AoD52CpC;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;;;AAIJ;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;AChJF;EACE;EACA;EACA;EACA;EACA;EACA,SrDyyCkC;;AqDvyClC;EACE;EACA;;;AAKJ;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAKA;EACE;;;AAIJ;EACE;IACE,SrD4wCgC;;;AqDxwCpC;EACE;EACA;EACA;;;AAGF;EACE;IACE;;;AH9CF;EACE;EACA;EACA;;;AIFF;EACE;EACA;;;AAFF;EACE;EACA;;;AAFF;EACE;EACA;;;AAFF;EACE;EACA;;;AAFF;EACE;EACA;;;AAFF;EACE;EACA;;;AAFF;EACE;EACA;;;AAFF;EACE;EACA;;;ACHF;EACE;EACA;;AAGE;EAGE;EACA;;;AATN;EACE;EACA;;AAGE;EAGE;EACA;;;AATN;EACE;EACA;;AAGE;EAGE;EACA;;;AATN;EACE;EACA;;AAGE;EAGE;EACA;;;AATN;EACE;EACA;;AAGE;EAGE;EACA;;;AATN;EACE;EACA;;AAGE;EAGE;EACA;;;AATN;EACE;EACA;;AAGE;EAGE;EACA;;;AATN;EACE;EACA;;AAGE;EAGE;EACA;;;AAOR;EACE;EACA;;AAGE;EAEE;EACA;;;AC1BN;EACE;EAEA;;;ACHF;EACE;EACA,KzD6c4B;EyD5c5B;EACA;EACA,uBzD2c4B;EyD1c5B;;AAEA;EACE;EACA,OzDuc0B;EyDtc1B,QzDsc0B;EyDrc1B;ExCIE,YwCHF;;AxCOE;EwCZJ;IxCaM;;;;AwCDJ;EACE;;;ACnBN;EACE;EACA;;AAEA;EACE;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAKF;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;ACrBJ;EACE;EACA;EACA;EACA;EACA,S3DimCkC;;;A2D9lCpC;EACE;EACA;EACA;EACA;EACA,S3DylCkC;;;A2DjlChC;EACE;EACA;EACA,S3D6kC8B;;;A2D1kChC;EACE;EACA;EACA,S3DukC8B;;;ASxiChC;EkDxCA;IACE;IACA;IACA,S3D6kC8B;;E2D1kChC;IACE;IACA;IACA,S3DukC8B;;;ASxiChC;EkDxCA;IACE;IACA;IACA,S3D6kC8B;;E2D1kChC;IACE;IACA;IACA,S3DukC8B;;;ASxiChC;EkDxCA;IACE;IACA;IACA,S3D6kC8B;;E2D1kChC;IACE;IACA;IACA,S3DukC8B;;;ASxiChC;EkDxCA;IACE;IACA;IACA,S3D6kC8B;;E2D1kChC;IACE;IACA;IACA,S3DukC8B;;;ASxiChC;EkDxCA;IACE;IACA;IACA,S3D6kC8B;;E2D1kChC;IACE;IACA;IACA,S3DukC8B;;;A4DtmCpC;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;ACRF;AAAA;ECIE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGA;AAAA;EACE;;;ACdF;EACE;EACA;EACA;EACA;EACA;EACA,S/DgcsC;E+D/btC;;;ACRJ;ECAE;EACA;EACA;;;ACNF;EACE;EACA;EACA;EACA;EACA;EACA,SlE2rB4B;;;AmE/nBtB;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAjBJ;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AASF;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAjBJ;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AASF;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AArBJ;AAcA;EAOI;EAAA;;;AAmBJ;AA1BA;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAjBJ;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AASF;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAjBJ;EACE;;;AAIA;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AAIJ;EAOI;;;AAKF;EAOI;;;AAnBN;EAOI;;;AAKF;EAOI;;;AAnBN;EAOI;;;AAKF;EAOI;;;AAnBN;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAjBJ;EACE;;;AAIA;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AAIJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAPJ;EAIQ;EAGJ;;;AAjBJ;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AASF;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;EAAA;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;AAPJ;EAOI;;;A1DVR;E0DGI;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;;A1DVR;E0DGI;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;;A1DVR;E0DGI;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;;A1DVR;E0DGI;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;;A1DVR;E0DGI;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;IAAA;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;;ACtDZ;ED+CQ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;;ACnCZ;ED4BQ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;EAPJ;IAOI;;;AEzEZ;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAgBA;;AAAA;;AAAA;ACmCA;AAAA;AAAA;AAAA;AAAA;EAKE,OtEhDS;;AsEiDT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE;;;AASF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE;;;AC3DF;EACE;IACE,uBAbY;;;ACUlB;EACE;IACE;;;AAGJ;EACE;IACE;;EAEF;IACE;IACA;;;AHuDJ;;AAAA;;AAAA;AI5EA;AAAA;AAAA;AAkBA;AAAA;AAAA;AJsEA;;AAAA;;AAAA;AA2BA;;AAAA;;AAAA;AAQA;;AAAA;;AAAA;AK3HA;EACE;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;IACE;;EAGF;IACE;;;AAIJ;EACE;IACE;;EAGF;IACE;;;ALsEJ;;AAAA;;AAAA","file":"app.css"} \ No newline at end of file diff --git a/src/assets/css/scrollStyles.css b/src/assets/css/scrollStyles.css new file mode 100644 index 0000000000..71248ac1b6 --- /dev/null +++ b/src/assets/css/scrollStyles.css @@ -0,0 +1,18 @@ +.customScroll { + overflow-y: scroll; +} +.customScroll::-webkit-scrollbar { + width: 5px; +} +.customScroll::-webkit-scrollbar-track { + background: #f1f1f1; + border-radius: 6px; +} +.customScroll::-webkit-scrollbar-thumb { + background: var(--bs-gray-500); + border-radius: 6px; +} +.customScroll::-webkit-scrollbar-thumb:hover { + background: var(--bs-gray-600); + border-radius: 6px; +} diff --git a/src/assets/images/blank.png b/src/assets/images/blank.png new file mode 100644 index 0000000000..ae6f25f049 Binary files /dev/null and b/src/assets/images/blank.png differ diff --git a/src/assets/images/defaultImg.png b/src/assets/images/defaultImg.png new file mode 100644 index 0000000000..310a79c130 Binary files /dev/null and b/src/assets/images/defaultImg.png differ diff --git a/src/assets/images/palisadoes_logo.png b/src/assets/images/palisadoes_logo.png new file mode 100644 index 0000000000..2e91c02233 Binary files /dev/null and b/src/assets/images/palisadoes_logo.png differ diff --git a/src/assets/images/talawa-logo-200x200.png b/src/assets/images/talawa-logo-200x200.png new file mode 100644 index 0000000000..62ab0a91c3 Binary files /dev/null and b/src/assets/images/talawa-logo-200x200.png differ diff --git a/src/assets/talawa-logo-dark-200x200.png b/src/assets/images/talawa-logo-dark-200x200.png similarity index 100% rename from src/assets/talawa-logo-dark-200x200.png rename to src/assets/images/talawa-logo-dark-200x200.png diff --git a/src/assets/images/talawa-logo-lite-200x200.png b/src/assets/images/talawa-logo-lite-200x200.png new file mode 100644 index 0000000000..a8d0a8fa7b Binary files /dev/null and b/src/assets/images/talawa-logo-lite-200x200.png differ diff --git a/src/App.css b/src/assets/scss/_colors.scss similarity index 100% rename from src/App.css rename to src/assets/scss/_colors.scss diff --git a/src/assets/scss/_general.scss b/src/assets/scss/_general.scss new file mode 100644 index 0000000000..f2309504ce --- /dev/null +++ b/src/assets/scss/_general.scss @@ -0,0 +1,63 @@ +:root { + --bs-body-font-family: Arial, Helvetica, sans-serif; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html { + overflow-x: hidden; +} + +body { + background-color: var(--bs-body-bg); +} + +#root { + min-height: 100vh; + background-color: #f2f7ff; +} + +input[type='checkbox'] { + transform: scale(1.5); +} +.form-switch { + padding-left: 3rem; +} +input[type='file']::file-selector-button { + background: var(--bs-gray-400); +} + +.shimmer { + animation-duration: 2.2s; + animation-fill-mode: forwards; + animation-iteration-count: infinite; + animation-name: shimmer; + animation-timing-function: linear; + background: var(--bs-gray-200); + background: linear-gradient(to right, #f6f6f6 8%, #f0f0f0 18%, #f6f6f6 33%); + background-size: 1200px 100%; +} + +@-webkit-keyframes shimmer { + 0% { + background-position: -100% 0; + } + + 100% { + background-position: 100% 0; + } +} + +@keyframes shimmer { + 0% { + background-position: -1200px 0; + } + + 100% { + background-position: 1200px 0; + } +} diff --git a/src/assets/scss/_talawa.scss b/src/assets/scss/_talawa.scss new file mode 100644 index 0000000000..2537c2c682 --- /dev/null +++ b/src/assets/scss/_talawa.scss @@ -0,0 +1,136 @@ +/* + TALAWA SCSS + ----------- + This file is used to import all partial scss files in the project. + It is used to compile the final CSS file to the CSS folder as main.css . + +========= Table of Contents ========= +1. Components +2. Content +3. Forms +4. Utilities +5. General +6. Colors + +*/ + +/* + + 1. COMPONENTS + +*/ + +// 1.1. Accordion +@import './components/accordion'; + +// 1.2. Alert +@import './components/alert'; + +// 1.3. Badge +@import './components/badge'; + +// 1.4. Breadcrumb +@import './components/breadcrumb'; + +// 1.5. Button +@import './components/buttons'; + +// 1.6. Card +@import './components/card'; + +// 1.7. Carousel +@import './components/carousel'; + +// 1.8. Close +@import './components/close'; + +// 1.9. Dropdown +@import './components/dropdown'; + +// 1.10. List Group +@import './components/list-group'; + +// 1.11. Modal +@import './components/modal'; + +// 1.12. Navbar +@import './components/navbar'; + +// 1.13. Nav and Nav Tabs +@import './components/nav'; + +// 1.14 Offcanvas +@import './components/offcanvas'; + +// 1.15 Pagination +@import './components/pagination'; + +// 1.16 Placeholder +@import './components/placeholder'; + +// 1.17 Progress +@import './components/progress'; + +// 1.18 Spinners +@import './components/spinners'; + +/* + + 2. CONTENT + +*/ + +// 2.1. Table +@import './content/table'; + +// 2.2. Typography +@import './content/typography'; + +/* + + 3. FORMS + +*/ + +// 3.1. Checkbox & Radio +@import './forms/check-radios'; + +// 3.2. Floating Labels +@import './forms/floating-label'; + +// 3.3. Form Controls +@import './forms/form-control'; + +// 3.4. Input Group +@import './forms/input-group'; + +// 3.5. Range +@import './forms/range'; + +// 3.6. Select +@import './forms/select'; + +// 3.7. Validation +@import './forms/validation'; + +/* + + 4. UTILITIES + +*/ + +@import './utilities'; + +/* + + 5. General + +*/ +@import './general'; + +/* + + 6. COLORS + +*/ +@import './colors'; diff --git a/src/assets/scss/_utilities.scss b/src/assets/scss/_utilities.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/assets/scss/_variables.scss b/src/assets/scss/_variables.scss new file mode 100644 index 0000000000..2871cb9df2 --- /dev/null +++ b/src/assets/scss/_variables.scss @@ -0,0 +1,30 @@ +// Colors + +$primary: #31bb6b; +$secondary: #707070; +$success: #31bb6b; +$warning: #febc59; + +$blue: #0d6efd; +$indigo: #6610f2; +$purple: #6f42c1; +$pink: #d63384; +$red: #dc3545; +$orange: #fd7e14; +$yellow: #ffc107; +$green: #198754; +$teal: #20c997; +$cyan: #0dcaf0; +$placeholder-bg: #f2f2f2; +// Colors + +// Links +$link-color: $blue !default; +$link-decoration: none !default; + +// Inputs and buttons +$input-bg: $placeholder-bg; +$input-border-width: 0; + +$input-btn-padding-y: 0.7rem; +$input-btn-padding-x: 1rem; diff --git a/src/assets/scss/app.scss b/src/assets/scss/app.scss new file mode 100644 index 0000000000..8685a742db --- /dev/null +++ b/src/assets/scss/app.scss @@ -0,0 +1,14 @@ +// Importing Bootstrap SCSS Functions and Mixins +@import '../../../node_modules/bootstrap/scss/functions'; +@import '../../../node_modules/bootstrap/scss/mixins'; + +// Importing Our Bootstrap SCSS Variables +@import './variables'; + +// Importing Bootstrap Variables and SCSS +@import '../../../node_modules/bootstrap/scss/variables'; +@import '../../../node_modules/bootstrap/scss/variables-dark'; +@import '../../../node_modules/bootstrap/scss/bootstrap.scss'; + +// Importing Our Bootstrap SCSS Overrides +@import './talawa'; diff --git a/src/assets/scss/components/_accordion.scss b/src/assets/scss/components/_accordion.scss new file mode 100644 index 0000000000..64eb323b55 --- /dev/null +++ b/src/assets/scss/components/_accordion.scss @@ -0,0 +1,36 @@ +$accordion-padding-y: 1.25rem; +$accordion-padding-x: 1.5rem; +$accordion-color: var(--#{$prefix}body-color); +$accordion-bg: var(--#{$prefix}body-bg); +$accordion-border-width: var(--#{$prefix}border-width); +$accordion-border-color: var(--#{$prefix}border-color); +$accordion-border-radius: var(--#{$prefix}border-radius); +$accordion-inner-border-radius: subtract( + $accordion-border-radius, + $accordion-border-width +); + +$accordion-body-padding-y: $accordion-padding-y; +$accordion-body-padding-x: $accordion-padding-x; + +$accordion-button-padding-y: $accordion-padding-y; +$accordion-button-padding-x: $accordion-padding-x; +$accordion-button-color: var(--#{$prefix}body-color); +$accordion-button-bg: var(--#{$prefix}accordion-bg); +$accordion-transition: + $btn-transition, + border-radius 0.15s ease; +$accordion-button-active-bg: var(--#{$prefix}primary-bg-subtle); +$accordion-button-active-color: var(--#{$prefix}primary-text-emphasis); + +$accordion-button-focus-border-color: $input-focus-border-color; +$accordion-button-focus-box-shadow: $btn-focus-box-shadow; + +$accordion-icon-width: 1.25rem; +$accordion-icon-color: $body-color; +$accordion-icon-active-color: $primary-text-emphasis; +$accordion-icon-transition: transform 0.2s ease-in-out; +$accordion-icon-transform: rotate(-180deg); + +$accordion-button-icon: url("data:image/svg+xml,"); +$accordion-button-active-icon: url("data:image/svg+xml,"); diff --git a/src/assets/scss/components/_alert.scss b/src/assets/scss/components/_alert.scss new file mode 100644 index 0000000000..64f29bf3c0 --- /dev/null +++ b/src/assets/scss/components/_alert.scss @@ -0,0 +1,10 @@ +$alert-padding-y: $spacer; +$alert-padding-x: $spacer; +$alert-margin-bottom: 1rem; +$alert-border-radius: var(--#{$prefix}border-radius); +$alert-link-font-weight: $font-weight-bold; +$alert-border-width: var(--#{$prefix}border-width); +$alert-bg-scale: -80%; +$alert-border-scale: -70%; +$alert-color-scale: 40%; +$alert-dismissible-padding-r: $alert-padding-x * 3; // 3x covers width of x plus default padding on either side diff --git a/src/assets/scss/components/_badge.scss b/src/assets/scss/components/_badge.scss new file mode 100644 index 0000000000..9b0c6a8a3a --- /dev/null +++ b/src/assets/scss/components/_badge.scss @@ -0,0 +1,6 @@ +$badge-font-size: 0.75em; +$badge-font-weight: $font-weight-bold; +$badge-color: $white; +$badge-padding-y: 0.35em; +$badge-padding-x: 0.65em; +$badge-border-radius: var(--#{$prefix}border-radius); diff --git a/src/assets/scss/components/_breadcrumb.scss b/src/assets/scss/components/_breadcrumb.scss new file mode 100644 index 0000000000..73fb6bd692 --- /dev/null +++ b/src/assets/scss/components/_breadcrumb.scss @@ -0,0 +1,11 @@ +$breadcrumb-font-size: null; +$breadcrumb-padding-y: 0; +$breadcrumb-padding-x: 0; +$breadcrumb-item-padding-x: 0.5rem; +$breadcrumb-margin-bottom: 1rem; +$breadcrumb-bg: null; +$breadcrumb-divider-color: var(--#{$prefix}secondary-color); +$breadcrumb-active-color: var(--#{$prefix}secondary-color); +$breadcrumb-divider: quote('/'); +$breadcrumb-divider-flipped: $breadcrumb-divider; +$breadcrumb-border-radius: null; diff --git a/src/assets/scss/components/_buttons.scss b/src/assets/scss/components/_buttons.scss new file mode 100644 index 0000000000..c0400fbeae --- /dev/null +++ b/src/assets/scss/components/_buttons.scss @@ -0,0 +1,73 @@ +$btn-color: $white; +$btn-padding-y: $input-btn-padding-y; +$btn-padding-x: $input-btn-padding-x; +$btn-font-family: $input-btn-font-family; +$btn-font-size: $input-btn-font-size; +$btn-line-height: $input-btn-line-height; +$btn-white-space: null; // Set to `nowrap` to prevent text wrapping + +$btn-padding-y-sm: $input-btn-padding-y-sm; +$btn-padding-x-sm: $input-btn-padding-x-sm; +$btn-font-size-sm: $input-btn-font-size-sm; + +$btn-padding-y-lg: $input-btn-padding-y-lg; +$btn-padding-x-lg: $input-btn-padding-x-lg; +$btn-font-size-lg: $input-btn-font-size-lg; + +$btn-border-width: $input-btn-border-width; + +$btn-font-weight: $font-weight-normal; +$btn-box-shadow: + inset 0 1px 0 rgba($white, 0.15), + 0 1px 1px rgba($black, 0.075); +$btn-focus-width: $input-btn-focus-width; +$btn-focus-box-shadow: $input-btn-focus-box-shadow; +$btn-disabled-opacity: 0.65; +$btn-active-box-shadow: inset 0 3px 5px rgba($black, 0.125); + +$btn-link-color: var(--#{$prefix}link-color); +$btn-link-hover-color: var(--#{$prefix}link-hover-color); +$btn-link-disabled-color: $gray-600; + +// Allows for customizing button radius independently from global border radius +$btn-border-radius: var(--#{$prefix}border-radius); +$btn-border-radius-sm: var(--#{$prefix}border-radius-sm); +$btn-border-radius-lg: var(--#{$prefix}border-radius-lg); + +$btn-transition: + color 0.15s ease-in-out, + background-color 0.15s ease-in-out, + border-color 0.15s ease-in-out, + box-shadow 0.15s ease-in-out; + +$btn-hover-bg-shade-amount: 15%; +$btn-hover-bg-tint-amount: 15%; +$btn-hover-border-shade-amount: 20%; +$btn-hover-border-tint-amount: 10%; +$btn-active-bg-shade-amount: 20%; +$btn-active-bg-tint-amount: 20%; +$btn-active-border-shade-amount: 25%; +$btn-active-border-tint-amount: 10%; + +.btn-primary, +.btn-secondary, +.btn-success, +.btn-warning, +.btn-info { + color: $white; + &:hover, + &:active { + color: $white !important; + } +} + +.btn-outline-primary, +.btn-outline-secondary, +.btn-outline-success, +.btn-outline-warning, +.btn-outline-info { + &:hover, + &:active { + color: $white !important; + } +} diff --git a/src/assets/scss/components/_card.scss b/src/assets/scss/components/_card.scss new file mode 100644 index 0000000000..5fa5abb4ee --- /dev/null +++ b/src/assets/scss/components/_card.scss @@ -0,0 +1,19 @@ +$card-spacer-y: $spacer; +$card-spacer-x: $spacer; +$card-title-spacer-y: $spacer * 0.5; +$card-title-color: null; +$card-subtitle-color: null; +$card-border-width: var(--#{$prefix}border-width); +$card-border-color: var(--#{$prefix}border-color-translucent); +$card-border-radius: var(--#{$prefix}border-radius); +$card-box-shadow: null; +$card-inner-border-radius: subtract($card-border-radius, $card-border-width); +$card-cap-padding-y: $card-spacer-y * 0.5; +$card-cap-padding-x: $card-spacer-x; +$card-cap-bg: rgba(var(--#{$prefix}body-color-rgb), 0.03); +$card-cap-color: null; +$card-height: null; +$card-color: null; +$card-bg: var(--#{$prefix}body-bg); +$card-img-overlay-padding: $spacer; +$card-group-margin: $grid-gutter-width * 0.5; diff --git a/src/assets/scss/components/_carousel.scss b/src/assets/scss/components/_carousel.scss new file mode 100644 index 0000000000..5f7d77e4c6 --- /dev/null +++ b/src/assets/scss/components/_carousel.scss @@ -0,0 +1,27 @@ +$carousel-control-color: $white; +$carousel-control-width: 15%; +$carousel-control-opacity: 0.5; +$carousel-control-hover-opacity: 0.9; +$carousel-control-transition: opacity 0.15s ease; + +$carousel-indicator-width: 30px; +$carousel-indicator-height: 3px; +$carousel-indicator-hit-area-height: 10px; +$carousel-indicator-spacer: 3px; +$carousel-indicator-opacity: 0.5; +$carousel-indicator-active-bg: $white; +$carousel-indicator-active-opacity: 1; +$carousel-indicator-transition: opacity 0.6s ease; + +$carousel-caption-width: 70%; +$carousel-caption-color: $white; +$carousel-caption-padding-y: 1.25rem; +$carousel-caption-spacer: 1.25rem; + +$carousel-control-icon-width: 2rem; + +$carousel-control-prev-icon-bg: url("data:image/svg+xml,"); +$carousel-control-next-icon-bg: url("data:image/svg+xml,"); + +$carousel-transition-duration: 0.6s; +$carousel-transition: transform $carousel-transition-duration ease-in-out; // Define transform transition first if using multiple transitions (e.g., `transform 2s ease, opacity .5s ease-out`) diff --git a/src/assets/scss/components/_close.scss b/src/assets/scss/components/_close.scss new file mode 100644 index 0000000000..2ae25d5353 --- /dev/null +++ b/src/assets/scss/components/_close.scss @@ -0,0 +1,12 @@ +$btn-close-width: 1em; +$btn-close-height: $btn-close-width; +$btn-close-padding-x: 0.25em; +$btn-close-padding-y: $btn-close-padding-x; +$btn-close-color: $black; +$btn-close-bg: url("data:image/svg+xml,"); +$btn-close-focus-shadow: $focus-ring-box-shadow; +$btn-close-opacity: 0.5; +$btn-close-hover-opacity: 0.75; +$btn-close-focus-opacity: 1; +$btn-close-disabled-opacity: 0.25; +$btn-close-white-filter: invert(1) grayscale(100%) brightness(200%); diff --git a/src/assets/scss/components/_dropdown.scss b/src/assets/scss/components/_dropdown.scss new file mode 100644 index 0000000000..1e1f1fa040 --- /dev/null +++ b/src/assets/scss/components/_dropdown.scss @@ -0,0 +1,35 @@ +$dropdown-min-width: 10rem; +$dropdown-padding-x: 0; +$dropdown-padding-y: 0.5rem; +$dropdown-spacer: 0.125rem; +$dropdown-font-size: $font-size-base; +$dropdown-color: var(--#{$prefix}body-color); +$dropdown-bg: var(--#{$prefix}body-bg); +$dropdown-border-color: var(--#{$prefix}border-color-translucent); +$dropdown-border-radius: var(--#{$prefix}border-radius); +$dropdown-border-width: var(--#{$prefix}border-width); +$dropdown-inner-border-radius: calc( + #{$dropdown-border-radius} - #{$dropdown-border-width} +); // stylelint-disable-line function-disallowed-list +$dropdown-divider-bg: $dropdown-border-color; +$dropdown-divider-margin-y: $spacer * 0.5; +$dropdown-box-shadow: $box-shadow; + +$dropdown-link-color: var(--#{$prefix}body-color); +$dropdown-link-hover-color: $dropdown-link-color; +$dropdown-link-hover-bg: var(--#{$prefix}tertiary-bg); + +$dropdown-link-active-color: $component-active-color; +$dropdown-link-active-bg: $component-active-bg; + +$dropdown-link-disabled-color: var(--#{$prefix}tertiary-color); + +$dropdown-item-padding-y: $spacer * 0.25; +$dropdown-item-padding-x: $spacer; + +$dropdown-header-color: $gray-600; +$dropdown-header-padding-x: $dropdown-item-padding-x; +$dropdown-header-padding-y: $dropdown-padding-y; +// fusv-disable +$dropdown-header-padding: $dropdown-header-padding-y $dropdown-header-padding-x; // Deprecated in v5.2.0 +// fusv-enable diff --git a/src/assets/scss/components/_list-group.scss b/src/assets/scss/components/_list-group.scss new file mode 100644 index 0000000000..2579f2e823 --- /dev/null +++ b/src/assets/scss/components/_list-group.scss @@ -0,0 +1,26 @@ +$list-group-color: var(--#{$prefix}body-color); +$list-group-bg: var(--#{$prefix}body-bg); +$list-group-border-color: var(--#{$prefix}border-color); +$list-group-border-width: var(--#{$prefix}border-width); +$list-group-border-radius: var(--#{$prefix}border-radius); + +$list-group-item-padding-y: $spacer * 0.5; +$list-group-item-padding-x: $spacer; +// fusv-disable +$list-group-item-bg-scale: -80%; // Deprecated in v5.3.0 +$list-group-item-color-scale: 40%; // Deprecated in v5.3.0 +// fusv-enable + +$list-group-hover-bg: var(--#{$prefix}tertiary-bg); +$list-group-active-color: $component-active-color; +$list-group-active-bg: $component-active-bg; +$list-group-active-border-color: $list-group-active-bg; + +$list-group-disabled-color: var(--#{$prefix}secondary-color); +$list-group-disabled-bg: $list-group-bg; + +$list-group-action-color: var(--#{$prefix}secondary-color); +$list-group-action-hover-color: var(--#{$prefix}emphasis-color); + +$list-group-action-active-color: var(--#{$prefix}body-color); +$list-group-action-active-bg: var(--#{$prefix}secondary-bg); diff --git a/src/assets/scss/components/_modal.scss b/src/assets/scss/components/_modal.scss new file mode 100644 index 0000000000..b491a19f1c --- /dev/null +++ b/src/assets/scss/components/_modal.scss @@ -0,0 +1,43 @@ +$modal-inner-padding: $spacer; + +$modal-footer-margin-between: 0.5rem; + +$modal-dialog-margin: 0.5rem; +$modal-dialog-margin-y-sm-up: 1.75rem; + +$modal-title-line-height: $line-height-base; + +$modal-content-color: null; +$modal-content-bg: var(--#{$prefix}body-bg); +$modal-content-border-color: var(--#{$prefix}border-color-translucent); +$modal-content-border-width: var(--#{$prefix}border-width); +$modal-content-border-radius: var(--#{$prefix}border-radius-lg); +$modal-content-inner-border-radius: subtract( + $modal-content-border-radius, + $modal-content-border-width +); +$modal-content-box-shadow-xs: $box-shadow-sm; +$modal-content-box-shadow-sm-up: $box-shadow; + +$modal-backdrop-bg: $black; +$modal-backdrop-opacity: 0.5; + +$modal-header-border-color: var(--#{$prefix}border-color); +$modal-header-border-width: 0; // We dont want border here +$modal-header-padding-y: $modal-inner-padding * 0.8; +$modal-header-padding-x: $modal-inner-padding; +$modal-header-padding: $modal-header-padding-y $modal-header-padding-x; // Keep this for backwards compatibility + +$modal-footer-bg: null; +$modal-footer-border-color: $modal-header-border-color; +$modal-footer-border-width: 0; // We don't want border here + +$modal-sm: 300px; +$modal-md: 500px; +$modal-lg: 800px; +$modal-xl: 1140px; + +$modal-fade-transform: translate(0, -50px); +$modal-show-transform: none; +$modal-transition: transform 0.3s ease-out; +$modal-scale-transform: scale(1.02); diff --git a/src/assets/scss/components/_nav.scss b/src/assets/scss/components/_nav.scss new file mode 100644 index 0000000000..84aeab343c --- /dev/null +++ b/src/assets/scss/components/_nav.scss @@ -0,0 +1,30 @@ +$nav-link-padding-y: 0.5rem; +$nav-link-padding-x: 1rem; +$nav-link-font-size: null; +$nav-link-font-weight: null; +$nav-link-color: var(--#{$prefix}link-color); +$nav-link-hover-color: var(--#{$prefix}link-hover-color); +$nav-link-transition: + color 0.15s ease-in-out, + background-color 0.15s ease-in-out, + border-color 0.15s ease-in-out; +$nav-link-disabled-color: var(--#{$prefix}secondary-color); +$nav-link-focus-box-shadow: $focus-ring-box-shadow; + +$nav-tabs-border-color: var(--#{$prefix}border-color); +$nav-tabs-border-width: var(--#{$prefix}border-width); +$nav-tabs-border-radius: var(--#{$prefix}border-radius); +$nav-tabs-link-hover-border-color: var(--#{$prefix}secondary-bg) + var(--#{$prefix}secondary-bg) $nav-tabs-border-color; +$nav-tabs-link-active-color: var(--#{$prefix}emphasis-color); +$nav-tabs-link-active-bg: var(--#{$prefix}body-bg); +$nav-tabs-link-active-border-color: var(--#{$prefix}border-color) + var(--#{$prefix}border-color) $nav-tabs-link-active-bg; + +$nav-pills-border-radius: var(--#{$prefix}border-radius); +$nav-pills-link-active-color: $component-active-color; +$nav-pills-link-active-bg: $component-active-bg; + +$nav-underline-gap: 1rem; +$nav-underline-border-width: 0.125rem; +$nav-underline-link-active-color: var(--#{$prefix}emphasis-color); diff --git a/src/assets/scss/components/_navbar.scss b/src/assets/scss/components/_navbar.scss new file mode 100644 index 0000000000..aaf27bc8b2 --- /dev/null +++ b/src/assets/scss/components/_navbar.scss @@ -0,0 +1,31 @@ +$navbar-padding-y: $spacer * 0.5; +$navbar-padding-x: null; + +$navbar-nav-link-padding-x: 0.5rem; + +$navbar-brand-font-size: $font-size-lg; +// Compute the navbar-brand padding-y so the navbar-brand will have the same height as navbar-text and nav-link +$nav-link-height: $font-size-base * $line-height-base + $nav-link-padding-y * 2; +$navbar-brand-height: $navbar-brand-font-size * $line-height-base; +$navbar-brand-padding-y: ($nav-link-height - $navbar-brand-height) * 0.5; +$navbar-brand-margin-end: 1rem; + +$navbar-toggler-padding-y: 0.25rem; +$navbar-toggler-padding-x: 0.75rem; +$navbar-toggler-font-size: $font-size-lg; +$navbar-toggler-border-radius: $btn-border-radius; +$navbar-toggler-focus-width: $btn-focus-width; +$navbar-toggler-transition: box-shadow 0.15s ease-in-out; + +$navbar-light-color: rgba(var(--#{$prefix}emphasis-color-rgb), 0.65); +$navbar-light-hover-color: rgba(var(--#{$prefix}emphasis-color-rgb), 0.8); +$navbar-light-active-color: rgba(var(--#{$prefix}emphasis-color-rgb), 1); +$navbar-light-disabled-color: rgba(var(--#{$prefix}emphasis-color-rgb), 0.3); +$navbar-light-icon-color: rgba($body-color, 0.75); +$navbar-light-toggler-icon-bg: url("data:image/svg+xml,"); +$navbar-light-toggler-border-color: rgba( + var(--#{$prefix}emphasis-color-rgb), + 0.15 +); +$navbar-light-brand-color: $navbar-light-active-color; +$navbar-light-brand-hover-color: $navbar-light-active-color; diff --git a/src/assets/scss/components/_offcanvas.scss b/src/assets/scss/components/_offcanvas.scss new file mode 100644 index 0000000000..3226f970f4 --- /dev/null +++ b/src/assets/scss/components/_offcanvas.scss @@ -0,0 +1,13 @@ +$offcanvas-padding-y: $modal-inner-padding; +$offcanvas-padding-x: $modal-inner-padding; +$offcanvas-horizontal-width: 400px; +$offcanvas-vertical-height: 30vh; +$offcanvas-transition-duration: 0.3s; +$offcanvas-border-color: $modal-content-border-color; +$offcanvas-border-width: $modal-content-border-width; +$offcanvas-title-line-height: $modal-title-line-height; +$offcanvas-bg-color: var(--#{$prefix}body-bg); +$offcanvas-color: var(--#{$prefix}body-color); +$offcanvas-box-shadow: $modal-content-box-shadow-xs; +$offcanvas-backdrop-bg: $modal-backdrop-bg; +$offcanvas-backdrop-opacity: $modal-backdrop-opacity; diff --git a/src/assets/scss/components/_pagination.scss b/src/assets/scss/components/_pagination.scss new file mode 100644 index 0000000000..830c140492 --- /dev/null +++ b/src/assets/scss/components/_pagination.scss @@ -0,0 +1,44 @@ +$pagination-padding-y: 0.375rem; +$pagination-padding-x: 0.75rem; +$pagination-padding-y-sm: 0.25rem; +$pagination-padding-x-sm: 0.5rem; +$pagination-padding-y-lg: 0.75rem; +$pagination-padding-x-lg: 1.5rem; + +$pagination-font-size: $font-size-base; + +$pagination-color: var(--#{$prefix}link-color); +$pagination-bg: var(--#{$prefix}body-bg); +$pagination-border-radius: var(--#{$prefix}border-radius); +$pagination-border-width: var(--#{$prefix}border-width); +$pagination-margin-start: calc( + #{$pagination-border-width} * -1 +); // stylelint-disable-line function-disallowed-list +$pagination-border-color: var(--#{$prefix}border-color); + +$pagination-focus-color: var(--#{$prefix}link-hover-color); +$pagination-focus-bg: var(--#{$prefix}secondary-bg); +$pagination-focus-box-shadow: $focus-ring-box-shadow; +$pagination-focus-outline: 0; + +$pagination-hover-color: var(--#{$prefix}link-hover-color); +$pagination-hover-bg: var(--#{$prefix}tertiary-bg); +$pagination-hover-border-color: var( + --#{$prefix}border-color +); // Todo in v6: remove this? + +$pagination-active-color: $component-active-color; +$pagination-active-bg: $component-active-bg; +$pagination-active-border-color: $component-active-bg; + +$pagination-disabled-color: var(--#{$prefix}secondary-color); +$pagination-disabled-bg: var(--#{$prefix}secondary-bg); +$pagination-disabled-border-color: var(--#{$prefix}border-color); + +$pagination-transition: + color 0.15s ease-in-out, + background-color 0.15s ease-in-out, + border-color 0.15s ease-in-out; + +$pagination-border-radius-sm: var(--#{$prefix}border-radius-sm); +$pagination-border-radius-lg: var(--#{$prefix}border-radius-lg); diff --git a/src/assets/scss/components/_placeholder.scss b/src/assets/scss/components/_placeholder.scss new file mode 100644 index 0000000000..8e7b77d0a4 --- /dev/null +++ b/src/assets/scss/components/_placeholder.scss @@ -0,0 +1,2 @@ +$placeholder-opacity-max: 0.5; +$placeholder-opacity-min: 0.2; diff --git a/src/assets/scss/components/_progress.scss b/src/assets/scss/components/_progress.scss new file mode 100644 index 0000000000..a40fa4676e --- /dev/null +++ b/src/assets/scss/components/_progress.scss @@ -0,0 +1,17 @@ +$progress-height: 1rem; +$progress-font-size: $font-size-base * 0.75; +$progress-bg: var(--#{$prefix}secondary-bg); +$progress-border-radius: var(--#{$prefix}border-radius); +$progress-box-shadow: var(--#{$prefix}box-shadow-inset); +$progress-bar-color: $white; +$progress-bar-bg: $primary; +$progress-bar-animation-timing: 1s linear infinite; +$progress-bar-transition: width 0.6s ease; + +@if $enable-transitions { + @keyframes progress-bar-stripes { + 0% { + background-position-x: $progress-height; + } + } +} diff --git a/src/assets/scss/components/_spinners.scss b/src/assets/scss/components/_spinners.scss new file mode 100644 index 0000000000..08f4c51c90 --- /dev/null +++ b/src/assets/scss/components/_spinners.scss @@ -0,0 +1,24 @@ +$spinner-width: 2rem; +$spinner-height: $spinner-width; +$spinner-vertical-align: -0.125em; +$spinner-border-width: 0.25em; +$spinner-animation-speed: 0.75s; + +$spinner-width-sm: 1rem; +$spinner-height-sm: $spinner-width-sm; +$spinner-border-width-sm: 0.2em; + +@keyframes spinner-border { + to { + transform: rotate(360deg) #{'/* rtl:ignore */'}; + } +} +@keyframes spinner-grow { + 0% { + transform: scale(0); + } + 50% { + opacity: 1; + transform: none; + } +} diff --git a/src/assets/scss/content/_table.scss b/src/assets/scss/content/_table.scss new file mode 100644 index 0000000000..f5c9c608fb --- /dev/null +++ b/src/assets/scss/content/_table.scss @@ -0,0 +1,37 @@ +$table-cell-padding-y: 0.5rem; +$table-cell-padding-x: 0.5rem; +$table-cell-padding-y-sm: 0.25rem; +$table-cell-padding-x-sm: 0.25rem; + +$table-cell-vertical-align: top; + +$table-color: var(--#{$prefix}body-color); +$table-bg: var(--#{$prefix}body-bg); +$table-accent-bg: transparent; + +$table-th-font-weight: null; + +$table-striped-color: $table-color; +$table-striped-bg-factor: 0.05; +$table-striped-bg: rgba($black, $table-striped-bg-factor); + +$table-active-color: $table-color; +$table-active-bg-factor: 0.1; +$table-active-bg: rgba($black, $table-active-bg-factor); + +$table-hover-color: $table-color; +$table-hover-bg-factor: 0.075; +$table-hover-bg: rgba($black, $table-hover-bg-factor); + +$table-border-factor: 0.1; +$table-border-width: var(--#{$prefix}border-width); +$table-border-color: var(--#{$prefix}border-color); + +$table-striped-order: odd; +$table-striped-columns-order: even; + +$table-group-separator-color: currentcolor; + +$table-caption-color: var(--#{$prefix}secondary-color); + +$table-bg-scale: -80%; diff --git a/src/assets/scss/content/_typography.scss b/src/assets/scss/content/_typography.scss new file mode 100644 index 0000000000..6336f8554e --- /dev/null +++ b/src/assets/scss/content/_typography.scss @@ -0,0 +1,69 @@ +/* + DISPLAY SASS VARIABLES +*/ + +$display-font-sizes: ( + 1: 5rem, + 2: 4.5rem, + 3: 4rem, + 4: 3.5rem, + 5: 3rem, + 6: 2.5rem, +); + +$display-font-family: null; +$display-font-style: null; +$display-font-weight: 300; +$display-line-height: $headings-line-height; + +/* + DISPLAY SASS VARIABLES +*/ + +$lead-font-size: $font-size-base * 1.25; +$lead-font-weight: 300; + +$small-font-size: 0.875em; + +$sub-sup-font-size: 0.75em; + +// fusv-disable +$text-muted: var(--#{$prefix}secondary-color); // Deprecated in 5.3.0 +// fusv-enable + +$headings-margin-bottom: $spacer * 0.5; +$headings-font-family: null; +$headings-font-style: null; +$headings-font-weight: 500; +$headings-line-height: 1.2; +$headings-color: inherit; + +$initialism-font-size: $small-font-size; + +$blockquote-margin-y: $spacer; +$blockquote-font-size: $font-size-base * 1.25; +$blockquote-footer-color: $gray-600; +$blockquote-footer-font-size: $small-font-size; + +$hr-margin-y: $spacer; +$hr-color: inherit; + +// fusv-disable +$hr-bg-color: null; // Deprecated in v5.2.0 +$hr-height: null; // Deprecated in v5.2.0 +// fusv-enable + +$hr-border-color: null; // Allows for inherited colors +$hr-border-width: var(--#{$prefix}border-width); +$hr-opacity: 0.25; + +$legend-margin-bottom: 0.5rem; +$legend-font-size: 1.5rem; +$legend-font-weight: null; + +$dt-font-weight: $font-weight-bold; + +$list-inline-padding: 0.5rem; + +$mark-padding: 0.1875em; +$mark-bg: $yellow-100; diff --git a/src/assets/scss/forms/_check-radios.scss b/src/assets/scss/forms/_check-radios.scss new file mode 100644 index 0000000000..1ed4d32fd0 --- /dev/null +++ b/src/assets/scss/forms/_check-radios.scss @@ -0,0 +1,34 @@ +$form-check-input-width: 1em; +$form-check-min-height: $font-size-base * $line-height-base; +$form-check-padding-start: $form-check-input-width + 0.5em; +$form-check-margin-bottom: 0.125rem; +$form-check-label-color: null; +$form-check-label-cursor: null; +$form-check-transition: null; + +$form-check-input-active-filter: brightness(90%); + +$form-check-input-bg: $input-bg; +$form-check-input-border: var(--#{$prefix}border-width) solid + var(--#{$prefix}border-color); +$form-check-input-border-radius: 0.25em; +$form-check-radio-border-radius: 50%; +$form-check-input-focus-border: $input-focus-border-color; +$form-check-input-focus-box-shadow: $focus-ring-box-shadow; + +$form-check-input-checked-color: $component-active-color; +$form-check-input-checked-bg-color: $component-active-bg; +$form-check-input-checked-border-color: $form-check-input-checked-bg-color; +$form-check-input-checked-bg-image: url("data:image/svg+xml,"); +$form-check-radio-checked-bg-image: url("data:image/svg+xml,"); + +$form-check-input-indeterminate-color: $component-active-color; +$form-check-input-indeterminate-bg-color: $component-active-bg; +$form-check-input-indeterminate-border-color: $form-check-input-indeterminate-bg-color; +$form-check-input-indeterminate-bg-image: url("data:image/svg+xml,"); + +$form-check-input-disabled-opacity: 0.5; +$form-check-label-disabled-opacity: $form-check-input-disabled-opacity; +$form-check-btn-check-disabled-opacity: $btn-disabled-opacity; + +$form-check-inline-margin-end: 1rem; diff --git a/src/assets/scss/forms/_floating-label.scss b/src/assets/scss/forms/_floating-label.scss new file mode 100644 index 0000000000..8ab47c4a25 --- /dev/null +++ b/src/assets/scss/forms/_floating-label.scss @@ -0,0 +1,14 @@ +$form-floating-height: add(3.5rem, $input-height-border); +$form-floating-line-height: 1.25; +$form-floating-padding-x: $input-padding-x; +$form-floating-padding-y: 1rem; +$form-floating-input-padding-t: 1.625rem; +$form-floating-input-padding-b: 0.625rem; +$form-floating-label-height: 1.5em; +$form-floating-label-opacity: 0.65; +$form-floating-label-transform: scale(0.85) translateY(-0.5rem) + translateX(0.15rem); +$form-floating-label-disabled-color: $gray-600; +$form-floating-transition: + opacity 0.1s ease-in-out, + transform 0.1s ease-in-out; diff --git a/src/assets/scss/forms/_form-control.scss b/src/assets/scss/forms/_form-control.scss new file mode 100644 index 0000000000..230b3ec76b --- /dev/null +++ b/src/assets/scss/forms/_form-control.scss @@ -0,0 +1,108 @@ +$input-btn-padding-y: 0.375rem; +$input-btn-padding-x: 0.75rem; +$input-btn-font-family: null; +$input-btn-font-size: $font-size-base; +$input-btn-line-height: $line-height-base; + +$input-btn-focus-width: $focus-ring-width; +$input-btn-focus-color-opacity: $focus-ring-opacity; +$input-btn-focus-color: $focus-ring-color; +$input-btn-focus-blur: $focus-ring-blur; +$input-btn-focus-box-shadow: $focus-ring-box-shadow; + +$input-btn-padding-y-sm: 0.25rem; +$input-btn-padding-x-sm: 0.5rem; +$input-btn-font-size-sm: $font-size-sm; + +$input-btn-padding-y-lg: 0.5rem; +$input-btn-padding-x-lg: 1rem; +$input-btn-font-size-lg: $font-size-lg; + +$input-btn-border-width: var(--#{$prefix}border-width); + +$input-padding-y: $input-btn-padding-y; +$input-padding-x: $input-btn-padding-x; +$input-font-family: $input-btn-font-family; +$input-font-size: $input-btn-font-size; +$input-font-weight: $font-weight-base; +$input-line-height: $input-btn-line-height; + +$input-padding-y-sm: $input-btn-padding-y-sm; +$input-padding-x-sm: $input-btn-padding-x-sm; +$input-font-size-sm: $input-btn-font-size-sm; + +$input-padding-y-lg: $input-btn-padding-y-lg; +$input-padding-x-lg: $input-btn-padding-x-lg; +$input-font-size-lg: $input-btn-font-size-lg; + +$input-bg: var(--#{$prefix}body-bg); +$input-disabled-color: null; +$input-disabled-bg: var(--#{$prefix}secondary-bg); +$input-disabled-border-color: null; + +$input-color: var(--#{$prefix}body-color); +$input-border-color: var(--#{$prefix}border-color); +$input-border-width: $input-btn-border-width; +$input-box-shadow: $box-shadow-inset; + +$input-border-radius: var(--#{$prefix}border-radius); +$input-border-radius-sm: var(--#{$prefix}border-radius-sm); +$input-border-radius-lg: var(--#{$prefix}border-radius-lg); + +$input-focus-bg: $input-bg; +$input-focus-border-color: tint-color($component-active-bg, 50%); +$input-focus-color: $input-color; +$input-focus-width: $input-btn-focus-width; +$input-focus-box-shadow: $input-btn-focus-box-shadow; + +$input-placeholder-color: var(--#{$prefix}secondary-color); +$input-plaintext-color: var(--#{$prefix}body-color); + +$input-height-border: calc( + #{$input-border-width} * 2 +); // stylelint-disable-line function-disallowed-list + +$input-height-inner: add($input-line-height * 1em, $input-padding-y * 2); +$input-height-inner-half: add($input-line-height * 0.5em, $input-padding-y); +$input-height-inner-quarter: add( + $input-line-height * 0.25em, + $input-padding-y * 0.5 +); + +$input-height: add( + $input-line-height * 1em, + add($input-padding-y * 2, $input-height-border, false) +); +$input-height-sm: add( + $input-line-height * 1em, + add($input-padding-y-sm * 2, $input-height-border, false) +); +$input-height-lg: add( + $input-line-height * 1em, + add($input-padding-y-lg * 2, $input-height-border, false) +); + +$input-transition: + border-color 0.15s ease-in-out, + box-shadow 0.15s ease-in-out; + +$form-color-width: 3rem; + +// Form Label Text +$form-label-margin-bottom: 0.5rem; +$form-label-font-size: null; +$form-label-font-style: null; +$form-label-font-weight: null; +$form-label-color: null; + +// Form Text +$form-text-margin-top: 0.25rem; +$form-text-font-size: $small-font-size; +$form-text-font-style: null; +$form-text-font-weight: null; +$form-text-color: var(--#{$prefix}secondary-color); + +// Form File Button +$form-file-button-color: $input-color; +$form-file-button-bg: var(--#{$prefix}tertiary-bg); +$form-file-button-hover-bg: var(--#{$prefix}secondary-bg); diff --git a/src/assets/scss/forms/_input-group.scss b/src/assets/scss/forms/_input-group.scss new file mode 100644 index 0000000000..cd50a59126 --- /dev/null +++ b/src/assets/scss/forms/_input-group.scss @@ -0,0 +1,6 @@ +$input-group-addon-padding-y: $input-padding-y; +$input-group-addon-padding-x: $input-padding-x; +$input-group-addon-font-weight: $input-font-weight; +$input-group-addon-color: $input-color; +$input-group-addon-bg: var(--#{$prefix}tertiary-bg); +$input-group-addon-border-color: $input-border-color; diff --git a/src/assets/scss/forms/_range.scss b/src/assets/scss/forms/_range.scss new file mode 100644 index 0000000000..c0cdc61171 --- /dev/null +++ b/src/assets/scss/forms/_range.scss @@ -0,0 +1,23 @@ +$form-range-track-width: 100%; +$form-range-track-height: 0.5rem; +$form-range-track-cursor: pointer; +$form-range-track-bg: var(--#{$prefix}tertiary-bg); +$form-range-track-border-radius: 1rem; +$form-range-track-box-shadow: $box-shadow-inset; + +$form-range-thumb-width: 1rem; +$form-range-thumb-height: $form-range-thumb-width; +$form-range-thumb-bg: $component-active-bg; +$form-range-thumb-border: 0; +$form-range-thumb-border-radius: 1rem; +$form-range-thumb-box-shadow: 0 0.1rem 0.25rem rgba($black, 0.1); +$form-range-thumb-focus-box-shadow: + 0 0 0 1px $body-bg, + $input-focus-box-shadow; +$form-range-thumb-focus-box-shadow-width: $input-focus-width; // For focus box shadow issue in Edge +$form-range-thumb-active-bg: tint-color($component-active-bg, 70%); +$form-range-thumb-disabled-bg: var(--#{$prefix}secondary-color); +$form-range-thumb-transition: + background-color 0.15s ease-in-out, + border-color 0.15s ease-in-out, + box-shadow 0.15s ease-in-out; diff --git a/src/assets/scss/forms/_select.scss b/src/assets/scss/forms/_select.scss new file mode 100644 index 0000000000..4d5c428636 --- /dev/null +++ b/src/assets/scss/forms/_select.scss @@ -0,0 +1,44 @@ +$form-select-padding-y: $input-padding-y; +$form-select-padding-x: $input-padding-x; +$form-select-font-family: $input-font-family; +$form-select-font-size: $input-font-size; +$form-select-indicator-padding: $form-select-padding-x * 3; // Extra padding for background-image +$form-select-font-weight: $input-font-weight; +$form-select-line-height: $input-line-height; +$form-select-color: $input-color; +$form-select-bg: $input-bg; +$form-select-disabled-color: null; +$form-select-disabled-bg: $input-disabled-bg; +$form-select-disabled-border-color: $input-disabled-border-color; +$form-select-bg-position: right $form-select-padding-x center; +$form-select-bg-size: 16px 12px; // In pixels because image dimensions +$form-select-indicator-color: $gray-800; +$form-select-indicator: url("data:image/svg+xml,"); + +$form-select-feedback-icon-padding-end: $form-select-padding-x * 2.5 + + $form-select-indicator-padding; +$form-select-feedback-icon-position: center right $form-select-indicator-padding; +$form-select-feedback-icon-size: $input-height-inner-half + $input-height-inner-half; + +$form-select-border-width: $input-border-width; +$form-select-border-color: $input-border-color; +$form-select-border-radius: $input-border-radius; +$form-select-box-shadow: $box-shadow-inset; + +$form-select-focus-border-color: $input-focus-border-color; +$form-select-focus-width: $input-focus-width; +$form-select-focus-box-shadow: 0 0 0 $form-select-focus-width + $input-btn-focus-color; + +$form-select-padding-y-sm: $input-padding-y-sm; +$form-select-padding-x-sm: $input-padding-x-sm; +$form-select-font-size-sm: $input-font-size-sm; +$form-select-border-radius-sm: $input-border-radius-sm; + +$form-select-padding-y-lg: $input-padding-y-lg; +$form-select-padding-x-lg: $input-padding-x-lg; +$form-select-font-size-lg: $input-font-size-lg; +$form-select-border-radius-lg: $input-border-radius-lg; + +$form-select-transition: $input-transition; diff --git a/src/assets/scss/forms/_validation.scss b/src/assets/scss/forms/_validation.scss new file mode 100644 index 0000000000..9877dfe327 --- /dev/null +++ b/src/assets/scss/forms/_validation.scss @@ -0,0 +1,20 @@ +$form-feedback-margin-top: $form-text-margin-top; +$form-feedback-font-size: $form-text-font-size; +$form-feedback-font-style: $form-text-font-style; +$form-feedback-valid-color: $success; +$form-feedback-invalid-color: $danger; + +$form-feedback-icon-valid-color: $form-feedback-valid-color; +$form-feedback-icon-valid: url("data:image/svg+xml,"); +$form-feedback-icon-invalid-color: $form-feedback-invalid-color; +$form-feedback-icon-invalid: url("data:image/svg+xml,"); + +$form-valid-color: $form-feedback-valid-color; +$form-valid-border-color: $form-feedback-valid-color; +$form-invalid-color: $form-feedback-invalid-color; +$form-invalid-border-color: $form-feedback-invalid-color; + +$form-valid-color-dark: $green-300; +$form-valid-border-color-dark: $green-300; +$form-invalid-color-dark: $red-300; +$form-invalid-border-color-dark: $red-300; diff --git a/src/assets/svgs/actionItem.svg b/src/assets/svgs/actionItem.svg new file mode 100644 index 0000000000..d660b378cd --- /dev/null +++ b/src/assets/svgs/actionItem.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/svgs/admin.svg b/src/assets/svgs/admin.svg new file mode 100644 index 0000000000..8ee42f611d --- /dev/null +++ b/src/assets/svgs/admin.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/svgs/agenda-category-icon.svg b/src/assets/svgs/agenda-category-icon.svg new file mode 100644 index 0000000000..8e3d4562f3 --- /dev/null +++ b/src/assets/svgs/agenda-category-icon.svg @@ -0,0 +1 @@ +checklist \ No newline at end of file diff --git a/src/assets/svgs/agenda-items.svg b/src/assets/svgs/agenda-items.svg new file mode 100644 index 0000000000..343d1808b4 --- /dev/null +++ b/src/assets/svgs/agenda-items.svg @@ -0,0 +1 @@ +notebook diff --git a/src/assets/svgs/angleLeft.svg b/src/assets/svgs/angleLeft.svg new file mode 100644 index 0000000000..a0362e5e38 --- /dev/null +++ b/src/assets/svgs/angleLeft.svg @@ -0,0 +1,5 @@ + + +angle-left + + \ No newline at end of file diff --git a/src/assets/svgs/angleRight.svg b/src/assets/svgs/angleRight.svg new file mode 100644 index 0000000000..4a3a498877 --- /dev/null +++ b/src/assets/svgs/angleRight.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svgs/article.svg b/src/assets/svgs/article.svg new file mode 100644 index 0000000000..e828aa40fc --- /dev/null +++ b/src/assets/svgs/article.svg @@ -0,0 +1,14 @@ + + + \ No newline at end of file diff --git a/src/assets/svgs/blockUser.svg b/src/assets/svgs/blockUser.svg new file mode 100644 index 0000000000..f9aef51775 --- /dev/null +++ b/src/assets/svgs/blockUser.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svgs/blockedUser.svg b/src/assets/svgs/blockedUser.svg new file mode 100644 index 0000000000..bbe0a51f84 --- /dev/null +++ b/src/assets/svgs/blockedUser.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svgs/cardItemDate.svg b/src/assets/svgs/cardItemDate.svg new file mode 100644 index 0000000000..e3e738a3dc --- /dev/null +++ b/src/assets/svgs/cardItemDate.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svgs/cardItemEvent.svg b/src/assets/svgs/cardItemEvent.svg new file mode 100644 index 0000000000..e37a084018 --- /dev/null +++ b/src/assets/svgs/cardItemEvent.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svgs/cardItemLocation.svg b/src/assets/svgs/cardItemLocation.svg new file mode 100644 index 0000000000..1518f97a75 --- /dev/null +++ b/src/assets/svgs/cardItemLocation.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svgs/chat.svg b/src/assets/svgs/chat.svg new file mode 100644 index 0000000000..72787fab78 --- /dev/null +++ b/src/assets/svgs/chat.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svgs/checkInRegistrants.svg b/src/assets/svgs/checkInRegistrants.svg new file mode 100644 index 0000000000..0a663e3876 --- /dev/null +++ b/src/assets/svgs/checkInRegistrants.svg @@ -0,0 +1 @@ +check_inCreated with Sketch. \ No newline at end of file diff --git a/src/assets/svgs/dashboard.svg b/src/assets/svgs/dashboard.svg new file mode 100644 index 0000000000..12e8b0fe63 --- /dev/null +++ b/src/assets/svgs/dashboard.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svgs/date.svg b/src/assets/svgs/date.svg new file mode 100644 index 0000000000..9baf0768c4 --- /dev/null +++ b/src/assets/svgs/date.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/svgs/event.svg b/src/assets/svgs/event.svg new file mode 100644 index 0000000000..3c73e7b04e --- /dev/null +++ b/src/assets/svgs/event.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svgs/eventDashboard.svg b/src/assets/svgs/eventDashboard.svg new file mode 100644 index 0000000000..769c57d315 --- /dev/null +++ b/src/assets/svgs/eventDashboard.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/assets/svgs/eventStats.svg b/src/assets/svgs/eventStats.svg new file mode 100644 index 0000000000..ffa43fdc4a --- /dev/null +++ b/src/assets/svgs/eventStats.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/svgs/events.svg b/src/assets/svgs/events.svg new file mode 100644 index 0000000000..95b8a3b587 --- /dev/null +++ b/src/assets/svgs/events.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svgs/flask.svg b/src/assets/svgs/flask.svg new file mode 100644 index 0000000000..599220a9d2 --- /dev/null +++ b/src/assets/svgs/flask.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/svgs/funds.svg b/src/assets/svgs/funds.svg new file mode 100644 index 0000000000..372a258577 --- /dev/null +++ b/src/assets/svgs/funds.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/svgs/key.svg b/src/assets/svgs/key.svg new file mode 100644 index 0000000000..a1f47615e8 --- /dev/null +++ b/src/assets/svgs/key.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svgs/listEventRegistrants.svg b/src/assets/svgs/listEventRegistrants.svg new file mode 100644 index 0000000000..4d2874d641 --- /dev/null +++ b/src/assets/svgs/listEventRegistrants.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/svgs/location.svg b/src/assets/svgs/location.svg new file mode 100644 index 0000000000..b75f616dd6 --- /dev/null +++ b/src/assets/svgs/location.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/svgs/logout.svg b/src/assets/svgs/logout.svg new file mode 100644 index 0000000000..e71a973f0d --- /dev/null +++ b/src/assets/svgs/logout.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svgs/media.svg b/src/assets/svgs/media.svg new file mode 100644 index 0000000000..956c1e9a19 --- /dev/null +++ b/src/assets/svgs/media.svg @@ -0,0 +1,14 @@ + + + \ No newline at end of file diff --git a/src/assets/svgs/newChat.svg b/src/assets/svgs/newChat.svg new file mode 100644 index 0000000000..e3609e2895 --- /dev/null +++ b/src/assets/svgs/newChat.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svgs/organizations.svg b/src/assets/svgs/organizations.svg new file mode 100644 index 0000000000..5c616655d2 --- /dev/null +++ b/src/assets/svgs/organizations.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/svgs/palisadoes.svg b/src/assets/svgs/palisadoes.svg new file mode 100644 index 0000000000..dc57b69a42 --- /dev/null +++ b/src/assets/svgs/palisadoes.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/svgs/people.svg b/src/assets/svgs/people.svg new file mode 100644 index 0000000000..cd8134aa67 --- /dev/null +++ b/src/assets/svgs/people.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svgs/plugins.svg b/src/assets/svgs/plugins.svg new file mode 100644 index 0000000000..7da1701dc1 --- /dev/null +++ b/src/assets/svgs/plugins.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/svgs/post.svg b/src/assets/svgs/post.svg new file mode 100644 index 0000000000..34e468523b --- /dev/null +++ b/src/assets/svgs/post.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svgs/posts.svg b/src/assets/svgs/posts.svg new file mode 100644 index 0000000000..181e25855a --- /dev/null +++ b/src/assets/svgs/posts.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svgs/requests.svg b/src/assets/svgs/requests.svg new file mode 100644 index 0000000000..ccf700e5fe --- /dev/null +++ b/src/assets/svgs/requests.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/svgs/roles.svg b/src/assets/svgs/roles.svg new file mode 100644 index 0000000000..bc301784f9 --- /dev/null +++ b/src/assets/svgs/roles.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svgs/settings.svg b/src/assets/svgs/settings.svg new file mode 100644 index 0000000000..fc111cfc08 --- /dev/null +++ b/src/assets/svgs/settings.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svgs/social-icons/Facebook-Logo.svg b/src/assets/svgs/social-icons/Facebook-Logo.svg new file mode 100644 index 0000000000..a70f112dc7 --- /dev/null +++ b/src/assets/svgs/social-icons/Facebook-Logo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svgs/social-icons/Github-Logo.svg b/src/assets/svgs/social-icons/Github-Logo.svg new file mode 100644 index 0000000000..7679af859c --- /dev/null +++ b/src/assets/svgs/social-icons/Github-Logo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svgs/social-icons/Instagram-Logo.svg b/src/assets/svgs/social-icons/Instagram-Logo.svg new file mode 100644 index 0000000000..cbf278ae75 --- /dev/null +++ b/src/assets/svgs/social-icons/Instagram-Logo.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/svgs/social-icons/Linkedin-Logo.svg b/src/assets/svgs/social-icons/Linkedin-Logo.svg new file mode 100644 index 0000000000..998dd1b826 --- /dev/null +++ b/src/assets/svgs/social-icons/Linkedin-Logo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svgs/social-icons/Reddit-Logo.svg b/src/assets/svgs/social-icons/Reddit-Logo.svg new file mode 100644 index 0000000000..8111415030 --- /dev/null +++ b/src/assets/svgs/social-icons/Reddit-Logo.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/svgs/social-icons/Slack-Logo.svg b/src/assets/svgs/social-icons/Slack-Logo.svg new file mode 100644 index 0000000000..29a9087d21 --- /dev/null +++ b/src/assets/svgs/social-icons/Slack-Logo.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/assets/svgs/social-icons/Twitter-Logo.svg b/src/assets/svgs/social-icons/Twitter-Logo.svg new file mode 100644 index 0000000000..efa659339d --- /dev/null +++ b/src/assets/svgs/social-icons/Twitter-Logo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svgs/social-icons/Youtube-Logo.svg b/src/assets/svgs/social-icons/Youtube-Logo.svg new file mode 100644 index 0000000000..112b9c2d3b --- /dev/null +++ b/src/assets/svgs/social-icons/Youtube-Logo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svgs/social-icons/index.tsx b/src/assets/svgs/social-icons/index.tsx new file mode 100644 index 0000000000..af6ef77966 --- /dev/null +++ b/src/assets/svgs/social-icons/index.tsx @@ -0,0 +1,19 @@ +import FacebookLogo from './Facebook-Logo.svg'; +import GithubLogo from './Github-Logo.svg'; +import InstagramLogo from './Instagram-Logo.svg'; +import LinkedInLogo from './Linkedin-Logo.svg'; +import SlackLogo from './Slack-Logo.svg'; +import TwitterLogo from './Twitter-Logo.svg'; +import YoutubeLogo from './Youtube-Logo.svg'; +import RedditLogo from './Reddit-Logo.svg'; + +export { + FacebookLogo, + GithubLogo, + InstagramLogo, + LinkedInLogo, + SlackLogo, + TwitterLogo, + YoutubeLogo, + RedditLogo, +}; diff --git a/src/assets/svgs/tags.svg b/src/assets/svgs/tags.svg new file mode 100644 index 0000000000..32cb76851a --- /dev/null +++ b/src/assets/svgs/tags.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svgs/talawa.svg b/src/assets/svgs/talawa.svg new file mode 100644 index 0000000000..0c89afbcca --- /dev/null +++ b/src/assets/svgs/talawa.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/svgs/user.svg b/src/assets/svgs/user.svg new file mode 100644 index 0000000000..b23b34481e --- /dev/null +++ b/src/assets/svgs/user.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/svgs/userEvent.svg b/src/assets/svgs/userEvent.svg new file mode 100644 index 0000000000..1623ca2e07 --- /dev/null +++ b/src/assets/svgs/userEvent.svg @@ -0,0 +1,14 @@ + + + \ No newline at end of file diff --git a/src/assets/svgs/users.svg b/src/assets/svgs/users.svg new file mode 100644 index 0000000000..a1a474206d --- /dev/null +++ b/src/assets/svgs/users.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svgs/venues.svg b/src/assets/svgs/venues.svg new file mode 100644 index 0000000000..c8cd52f4e7 --- /dev/null +++ b/src/assets/svgs/venues.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/talawa-logo-lite-200x200.png b/src/assets/talawa-logo-lite-200x200.png deleted file mode 100644 index 9d34137661..0000000000 Binary files a/src/assets/talawa-logo-lite-200x200.png and /dev/null differ diff --git a/src/components/ActionItems/ActionItemsContainer.module.css b/src/components/ActionItems/ActionItemsContainer.module.css new file mode 100644 index 0000000000..b55328c563 --- /dev/null +++ b/src/components/ActionItems/ActionItemsContainer.module.css @@ -0,0 +1,25 @@ +.actionItemStatusBadge { + width: 5.5rem; + margin-left: 1.1rem; +} + +.createModal { + margin-top: 20vh; + margin-left: 13vw; + max-width: 80vw; +} + +.titlemodal { + color: var(--bs-gray-600); + font-weight: 600; + font-size: 20px; + margin-bottom: 20px; + padding-bottom: 5px; + border-bottom: 3px solid var(--bs-primary); + width: 65%; +} + +.actionItemsOptionsButton { + width: 24px; + height: 24px; +} diff --git a/src/components/ActionItems/ActionItemsContainer.test.tsx b/src/components/ActionItems/ActionItemsContainer.test.tsx new file mode 100644 index 0000000000..7cb9c9e9bb --- /dev/null +++ b/src/components/ActionItems/ActionItemsContainer.test.tsx @@ -0,0 +1,777 @@ +import React from 'react'; +import { + render, + screen, + fireEvent, + waitFor, + act, + waitForElementToBeRemoved, +} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import 'jest-localstorage-mock'; +import { MockedProvider } from '@apollo/client/testing'; +import 'jest-location-mock'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import i18nForTest from 'utils/i18nForTest'; +import { toast } from 'react-toastify'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; + +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; + +import ActionItemsContainer from './ActionItemsContainer'; +import { props, props2 } from './ActionItemsContainerProps'; +import { MOCKS, MOCKS_ERROR_MUTATIONS } from './ActionItemsContainerMocks'; + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(MOCKS_ERROR_MUTATIONS, true); + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +jest.mock('@mui/x-date-pickers/DateTimePicker', () => { + return { + DateTimePicker: jest.requireActual( + '@mui/x-date-pickers/DesktopDateTimePicker', + ).DesktopDateTimePicker, + }; +}); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const translations = JSON.parse( + JSON.stringify( + i18nForTest.getDataByLanguage('en')?.translation.organizationActionItems, + ), +); + +describe('Testing Action Item Categories Component', () => { + const formData = { + assignee: 'Scott Norris', + preCompletionNotes: 'pre completion notes edited', + dueDate: '02/14/2024', + completionDate: '02/21/2024', + }; + + test('component loads correctly with action items', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.queryByText(translations.noActionItems), + ).not.toBeInTheDocument(); + }); + + expect(screen.getByText('#')).toBeInTheDocument(); + expect(screen.getByText(translations.assignee)).toBeInTheDocument(); + expect( + screen.getByText(translations.actionItemCategory), + ).toBeInTheDocument(); + expect( + screen.getByText(translations.preCompletionNotes), + ).toBeInTheDocument(); + expect( + screen.getByText(translations.postCompletionNotes), + ).toBeInTheDocument(); + + await wait(); + expect(screen.getAllByText('Harve Lance')[0]).toBeInTheDocument(); + + const asigneeAnchorElement = screen.getAllByText('Harve Lance')[0]; + expect(asigneeAnchorElement.tagName).toBe('A'); + expect(asigneeAnchorElement).toHaveAttribute('href', '/member/event1'); + + expect(screen.getAllByText('ActionItemCategory 1')[0]).toBeInTheDocument(); + const updateButtons = screen.getAllByTestId('editActionItemModalBtn'); + const previewButtons = screen.getAllByTestId('previewActionItemModalBtn'); + const updateStatusButtons = screen.getAllByTestId( + 'actionItemStatusChangeCheckbox', + ); + expect(updateButtons[0]).toBeInTheDocument(); + expect(previewButtons[0]).toBeInTheDocument(); + expect(updateStatusButtons[0]).toBeInTheDocument(); + }); + + test('component loads correctly with no action items', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.queryByText(translations.noActionItems), + ).toBeInTheDocument(); + }); + }); + + test('opens and closes the update modal correctly', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('editActionItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('editActionItemModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('updateActionItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('updateActionItemModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('updateActionItemModalCloseBtn'), + ); + }); + + test('opens and closes the action item status change modal correctly', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('actionItemStatusChangeCheckbox')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('actionItemStatusChangeCheckbox')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('actionItemStatusChangeModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('actionItemStatusChangeModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('actionItemStatusChangeModalCloseBtn'), + ); + }); + + test('completed action item status change modal loads correctly', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('actionItemStatusChangeCheckbox')[1], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('actionItemStatusChangeCheckbox')[1]); + + await waitFor(() => { + return expect( + screen.findByTestId('actionItemStatusChangeModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + expect(screen.getByText(translations.actionItemStatus)).toBeInTheDocument(); + + expect( + screen.getByTestId('actionItemsStatusChangeNotes'), + ).toBeInTheDocument(); + expect( + screen.getByPlaceholderText(translations.actionItemCompleted), + ).toBeInTheDocument(); + expect( + screen.getByRole('button', { name: translations.makeActive }), + ).toBeInTheDocument(); + }); + + test('opens and closes the preview modal correctly', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('previewActionItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('previewActionItemModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('previewActionItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('previewActionItemModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('previewActionItemModalCloseBtn'), + ); + }); + + test('opens and closes the update and delete modals through the preview modal', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('previewActionItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('previewActionItemModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('previewActionItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + await waitFor(() => { + expect( + screen.getByTestId('deleteActionItemPreviewModalBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteActionItemPreviewModalBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('actionItemDeleteModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('actionItemDeleteModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('actionItemDeleteModalCloseBtn'), + ); + + await waitFor(() => { + expect( + screen.getByTestId('editActionItemPreviewModalBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('editActionItemPreviewModalBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('updateActionItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('updateActionItemModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('updateActionItemModalCloseBtn'), + ); + }); + + test('updates an action item and toasts success', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('editActionItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('editActionItemModalBtn')[0]); + + await waitFor(() => { + expect(screen.getByTestId('formUpdateAssignee')).toBeInTheDocument(); + }); + + userEvent.selectOptions( + screen.getByTestId('formUpdateAssignee'), + formData.assignee, + ); + + const preCompletionNotes = screen.getByPlaceholderText( + translations.preCompletionNotes, + ); + fireEvent.change(preCompletionNotes, { target: { value: '' } }); + userEvent.type(preCompletionNotes, formData.preCompletionNotes); + + // const postCompletionNotes = screen.getByPlaceholderText( + // translations.postCompletionNotes, + // ); + // fireEvent.change(postCompletionNotes, { target: { value: '' } }); + // userEvent.type(postCompletionNotes, formData.postCompletionNotes); + + const dueDatePicker = screen.getByLabelText(translations.dueDate); + fireEvent.change(dueDatePicker, { + target: { value: formData.dueDate }, + }); + + const completionDatePicker = screen.getByLabelText( + translations.completionDate, + ); + fireEvent.change(completionDatePicker, { + target: { value: formData.completionDate }, + }); + + // await waitFor(() => { + // expect(screen.getByTestId('alldayCheck')).toBeInTheDocument(); + // }); + // userEvent.click(screen.getByTestId('alldayCheck')); + + await waitFor(() => { + expect(screen.getByTestId('editActionItemBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('editActionItemBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.successfulUpdation); + }); + }); + + test('toasts error on unsuccessful updation', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('editActionItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('editActionItemModalBtn')[0]); + + await waitFor(() => { + expect(screen.getByTestId('formUpdateAssignee')).toBeInTheDocument(); + }); + + userEvent.selectOptions( + screen.getByTestId('formUpdateAssignee'), + formData.assignee, + ); + + const preCompletionNotes = screen.getByPlaceholderText( + translations.preCompletionNotes, + ); + fireEvent.change(preCompletionNotes, { target: { value: '' } }); + userEvent.type(preCompletionNotes, formData.preCompletionNotes); + + // const postCompletionNotes = screen.getByPlaceholderText( + // translations.postCompletionNotes, + // ); + // fireEvent.change(postCompletionNotes, { target: { value: '' } }); + // userEvent.type(postCompletionNotes, formData.postCompletionNotes); + + const dueDatePicker = screen.getByLabelText(translations.dueDate); + fireEvent.change(dueDatePicker, { + target: { value: formData.dueDate }, + }); + + const completionDatePicker = screen.getByLabelText( + translations.completionDate, + ); + fireEvent.change(completionDatePicker, { + target: { value: formData.completionDate }, + }); + + // await waitFor(() => { + // expect(screen.getByTestId('alldayCheck')).toBeInTheDocument(); + // }); + // userEvent.click(screen.getByTestId('alldayCheck')); + + await waitFor(() => { + expect(screen.getByTestId('editActionItemBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('editActionItemBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); + + test('updates an action item status through the action item status change modal', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('actionItemStatusChangeCheckbox')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('actionItemStatusChangeCheckbox')[0]); + + await waitFor(() => { + expect( + screen.getByTestId('actionItemsStatusChangeNotes'), + ).toBeInTheDocument(); + }); + + const postCompletionNotes = screen.getByTestId( + 'actionItemsStatusChangeNotes', + ); + fireEvent.change(postCompletionNotes, { target: { value: '' } }); + userEvent.type( + postCompletionNotes, + 'this action item has been completed successfully', + ); + + await waitFor(() => { + expect( + screen.getByTestId('actionItemStatusChangeSubmitBtn'), + ).toBeInTheDocument(); + }); + expect( + screen.getByTestId('actionItemStatusChangeSubmitBtn'), + ).toHaveTextContent(translations.markCompletion); + userEvent.click(screen.getByTestId('actionItemStatusChangeSubmitBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.successfulUpdation); + }); + + await waitFor(() => { + expect( + screen.getAllByTestId('actionItemStatusChangeCheckbox')[1], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('actionItemStatusChangeCheckbox')[1]); + + await waitFor(() => { + expect( + screen.getByTestId('actionItemsStatusChangeNotes'), + ).toBeInTheDocument(); + }); + + const preCompletionNotes = screen.getByTestId( + 'actionItemsStatusChangeNotes', + ); + fireEvent.change(preCompletionNotes, { target: { value: '' } }); + userEvent.type( + preCompletionNotes, + 'this action item has been made active again', + ); + + await waitFor(() => { + expect( + screen.getByTestId('actionItemStatusChangeSubmitBtn'), + ).toBeInTheDocument(); + }); + expect( + screen.getByTestId('actionItemStatusChangeSubmitBtn'), + ).toHaveTextContent(translations.makeActive); + userEvent.click(screen.getByTestId('actionItemStatusChangeSubmitBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.successfulUpdation); + }); + }); + + test('deletes the action item and toasts success', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('previewActionItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('previewActionItemModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('previewActionItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + await waitFor(() => { + expect( + screen.getByTestId('deleteActionItemPreviewModalBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteActionItemPreviewModalBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('actionItemDeleteModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('deleteActionItemBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.successfulDeletion); + }); + }); + + test('toasts error on unsuccessful deletion', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('previewActionItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('previewActionItemModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('previewActionItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + await waitFor(() => { + expect( + screen.getByTestId('deleteActionItemPreviewModalBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteActionItemPreviewModalBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('actionItemDeleteModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteActionItemBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); + + test('shows the overlay text on action item notes', async () => { + const { getAllByTestId } = render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('actionItemPreCompletionNotesOverlay')[0], + ).toBeInTheDocument(); + }); + + await waitFor(() => { + fireEvent.mouseEnter( + getAllByTestId('actionItemPreCompletionNotesOverlay')[0], + ); + }); + + await waitFor(() => { + expect(screen.getByTestId('popover-actionItem1')).toBeInTheDocument(); + }); + + await waitFor(() => { + fireEvent.mouseLeave( + getAllByTestId('actionItemPreCompletionNotesOverlay')[0], + ); + }); + + await waitFor(() => { + fireEvent.mouseEnter( + getAllByTestId('actionItemPostCompletionNotesOverlay')[0], + ); + }); + + await waitFor(() => { + expect(screen.getByTestId('popover-actionItem2')).toBeInTheDocument(); + }); + + await waitFor(() => { + fireEvent.mouseLeave( + getAllByTestId('actionItemPostCompletionNotesOverlay')[0], + ); + }); + }); + + test('Action Items loads with correct headers', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + const actionItemHeaders = screen.getByTestId('actionItemsHeader'); + expect(actionItemHeaders).toBeInTheDocument(); + expect(screen.getByText(translations.assignee)).toBeInTheDocument(); + expect( + screen.getByText(translations.actionItemCategory), + ).toBeInTheDocument(); + expect( + screen.getByText(translations.preCompletionNotes), + ).toBeInTheDocument(); + expect( + screen.getByText(translations.postCompletionNotes), + ).toBeInTheDocument(); + expect(screen.getByText(translations.options)).toBeInTheDocument(); + }); +}); diff --git a/src/components/ActionItems/ActionItemsContainer.tsx b/src/components/ActionItems/ActionItemsContainer.tsx new file mode 100644 index 0000000000..42e57f3822 --- /dev/null +++ b/src/components/ActionItems/ActionItemsContainer.tsx @@ -0,0 +1,499 @@ +import React, { useState } from 'react'; +import dayjs from 'dayjs'; +import type { ChangeEvent } from 'react'; +import { + Button, + Col, + Form, + Modal, + OverlayTrigger, + Popover, + Row, +} from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; + +import { + DELETE_ACTION_ITEM_MUTATION, + UPDATE_ACTION_ITEM_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import { useMutation } from '@apollo/client'; + +import type { + InterfaceActionItemInfo, + InterfaceMemberInfo, +} from 'utils/interfaces'; +import styles from './ActionItemsContainer.module.css'; +import ActionItemUpdateModal from '../../screens/OrganizationActionItems/ActionItemUpdateModal'; +import ActionItemPreviewModal from '../../screens/OrganizationActionItems/ActionItemPreviewModal'; +import ActionItemDeleteModal from '../../screens/OrganizationActionItems/ActionItemDeleteModal'; +import { Link } from 'react-router-dom'; + +function actionItemsContainer({ + actionItemsConnection, + actionItemsData, + membersData, + actionItemsRefetch, +}: { + actionItemsConnection: 'Organization' | 'Event'; + actionItemsData: InterfaceActionItemInfo[] | undefined; + membersData: InterfaceMemberInfo[] | undefined; + actionItemsRefetch: () => void; +}): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'organizationActionItems', + }); + const { t: tCommon } = useTranslation('common'); + + const [actionItemPreviewModalIsOpen, setActionItemPreviewModalIsOpen] = + useState(false); + const [actionItemUpdateModalIsOpen, setActionItemUpdateModalIsOpen] = + useState(false); + const [actionItemDeleteModalIsOpen, setActionItemDeleteModalIsOpen] = + useState(false); + const [actionItemStatusModal, setActionItemStatusModal] = useState(false); + const [isActionItemCompleted, setIsActionItemCompleted] = useState(false); + + const [assignmentDate, setAssignmentDate] = useState(new Date()); + const [dueDate, setDueDate] = useState(new Date()); + const [completionDate, setCompletionDate] = useState(new Date()); + const [actionItemId, setActionItemId] = useState(''); + const [actionItemNotes, setActionItemNotes] = useState(''); + + const [formState, setFormState] = useState({ + assignee: '', + assigner: '', + assigneeId: '', + preCompletionNotes: '', + postCompletionNotes: '', + isCompleted: false, + }); + + const showPreviewModal = (actionItem: InterfaceActionItemInfo): void => { + setActionItemState(actionItem); + setActionItemPreviewModalIsOpen(true); + }; + + const showUpdateModal = (): void => { + setActionItemUpdateModalIsOpen(!actionItemUpdateModalIsOpen); + }; + + const hidePreviewModal = (): void => { + setActionItemPreviewModalIsOpen(false); + }; + + const hideUpdateModal = (): void => { + setActionItemId(''); + setActionItemUpdateModalIsOpen(!actionItemUpdateModalIsOpen); + }; + + const toggleDeleteModal = (): void => { + setActionItemDeleteModalIsOpen(!actionItemDeleteModalIsOpen); + }; + + const [updateActionItem] = useMutation(UPDATE_ACTION_ITEM_MUTATION); + + const updateActionItemHandler = async ( + e: ChangeEvent, + ): Promise => { + e.preventDefault(); + try { + await updateActionItem({ + variables: { + actionItemId, + assigneeId: formState.assigneeId, + preCompletionNotes: formState.preCompletionNotes, + postCompletionNotes: formState.postCompletionNotes, + dueDate: dayjs(dueDate).format('YYYY-MM-DD'), + completionDate: dayjs(completionDate).format('YYYY-MM-DD'), + isCompleted: formState.isCompleted, + }, + }); + + actionItemsRefetch(); + hideUpdateModal(); + toast.success(t('successfulUpdation')); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + console.log(error.message); + } + } + }; + + const [removeActionItem] = useMutation(DELETE_ACTION_ITEM_MUTATION); + const deleteActionItemHandler = async (): Promise => { + try { + await removeActionItem({ + variables: { + actionItemId, + }, + }); + + actionItemsRefetch(); + toggleDeleteModal(); + toast.success(t('successfulDeletion')); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + console.log(error.message); + } + } + }; + + const handleEditClick = (actionItem: InterfaceActionItemInfo): void => { + setActionItemState(actionItem); + showUpdateModal(); + }; + + const handleActionItemStatusChange = ( + actionItem: InterfaceActionItemInfo, + ): void => { + actionItem = { ...actionItem, isCompleted: !actionItem.isCompleted }; + setIsActionItemCompleted(!actionItem.isCompleted); + setActionItemState(actionItem); + setActionItemStatusModal(true); + }; + + const hideActionItemStatusModal = (): void => { + setActionItemStatusModal(false); + }; + + const setActionItemState = (actionItem: InterfaceActionItemInfo): void => { + setFormState({ + ...formState, + assignee: `${actionItem.assignee.firstName} ${actionItem.assignee.lastName}`, + assigner: `${actionItem.assigner.firstName} ${actionItem.assigner.lastName}`, + assigneeId: actionItem.assignee._id, + preCompletionNotes: actionItem.preCompletionNotes, + postCompletionNotes: actionItem.postCompletionNotes, + isCompleted: actionItem.isCompleted, + }); + setActionItemId(actionItem._id); + setDueDate(actionItem.dueDate); + setAssignmentDate(actionItem.assignmentDate); + setCompletionDate(actionItem.completionDate); + }; + + const popover = ( + + {actionItemNotes} + + ); + + return ( + <> +
+
+ + +
{'#'}
+ + +
{t('assignee')}
+ + + {t('actionItemCategory')} + + +
{t('preCompletionNotes')}
+ + +
{t('postCompletionNotes')}
+ + +
{t('options')}
+ +
+
+ +
+ {actionItemsData?.map((actionItem, index) => ( +
+ + + {index + 1} + + + + {`${actionItem.assignee.firstName} ${actionItem.assignee.lastName}`} + + + + {actionItem.actionItemCategory.name} + + +
+ + { + setActionItemId(actionItem._id); + setActionItemNotes(actionItem.preCompletionNotes); + }} + > + {actionItem.preCompletionNotes.length > 25 + ? `${actionItem.preCompletionNotes.substring(0, 25)}...` + : actionItem.preCompletionNotes} + + +
+ + +
+ {actionItem.isCompleted ? ( + + { + setActionItemId(actionItem._id); + setActionItemNotes(actionItem.postCompletionNotes); + }} + className="ms-3 " + > + {actionItem.postCompletionNotes?.length > 25 + ? `${actionItem.postCompletionNotes.substring(0, 25)}...` + : actionItem.postCompletionNotes} + + + ) : ( + + {t('actionItemActive')} + + )} +
+ + +
+ handleActionItemStatusChange(actionItem)} + /> + + +
+ +
+ + {index !== actionItemsData.length - 1 &&
} +
+ ))} + + {actionItemsData?.length === 0 && ( +
+ {t('noActionItems')} +
+ )} +
+
+ + {/* action item status change modal */} + + +

{t('actionItemStatus')}

+ +
+ +
+ + {isActionItemCompleted + ? t('preCompletionNotes') + : t('postCompletionNotes')} + + { + if (isActionItemCompleted) { + setFormState({ + ...formState, + preCompletionNotes: e.target.value, + }); + } else { + setFormState({ + ...formState, + postCompletionNotes: e.target.value, + }); + } + }} + /> + + +
+
+ + {/* preview modal */} + + + {/* Update Modal */} + + + {/* Delete Modal */} + + + ); +} + +export default actionItemsContainer; diff --git a/src/components/ActionItems/ActionItemsContainerMocks.ts b/src/components/ActionItems/ActionItemsContainerMocks.ts new file mode 100644 index 0000000000..a2dc20c5eb --- /dev/null +++ b/src/components/ActionItems/ActionItemsContainerMocks.ts @@ -0,0 +1,112 @@ +import { + UPDATE_ACTION_ITEM_MUTATION, + DELETE_ACTION_ITEM_MUTATION, +} from 'GraphQl/Mutations/mutations'; + +export const MOCKS = [ + { + request: { + query: UPDATE_ACTION_ITEM_MUTATION, + variables: { + actionItemId: 'actionItem1', + assigneeId: 'user2', + preCompletionNotes: 'pre completion notes edited', + postCompletionNotes: 'Post Completion Notes', + dueDate: '2024-02-14', + completionDate: '2024-02-21', + isCompleted: false, + }, + }, + result: { + data: { + updateActionItem: { + _id: 'actionItem1', + }, + }, + }, + }, + { + request: { + query: UPDATE_ACTION_ITEM_MUTATION, + variables: { + actionItemId: 'actionItem1', + assigneeId: 'user1', + preCompletionNotes: 'Pre Completion Notes', + postCompletionNotes: 'this action item has been completed successfully', + dueDate: '2024-02-21', + completionDate: '2024-02-21', + isCompleted: true, + }, + }, + result: { + data: { + updateActionItem: { + _id: 'actionItem1', + }, + }, + }, + }, + { + request: { + query: UPDATE_ACTION_ITEM_MUTATION, + variables: { + actionItemId: 'actionItem2', + assigneeId: 'user1', + preCompletionNotes: 'this action item has been made active again', + postCompletionNotes: 'Post Completion Notes', + dueDate: '2024-02-21', + completionDate: '2024-02-21', + isCompleted: false, + }, + }, + result: { + data: { + updateActionItem: { + _id: 'actionItem1', + }, + }, + }, + }, + { + request: { + query: DELETE_ACTION_ITEM_MUTATION, + variables: { + actionItemId: 'actionItem1', + }, + }, + result: { + data: { + removeActionItem: { + _id: 'actionItem1', + }, + }, + }, + }, +]; + +export const MOCKS_ERROR_MUTATIONS = [ + { + request: { + query: UPDATE_ACTION_ITEM_MUTATION, + variables: { + actionItemId: 'actionItem1', + assigneeId: 'user2', + preCompletionNotes: 'pre completion notes edited', + postCompletionNotes: '', + dueDate: '2024-02-14', + completionDate: '2024-02-21', + isCompleted: false, + }, + }, + error: new Error('Mock Graphql Error'), + }, + { + request: { + query: DELETE_ACTION_ITEM_MUTATION, + variables: { + actionItemId: 'actionItem1', + }, + }, + error: new Error('Mock Graphql Error'), + }, +]; diff --git a/src/components/ActionItems/ActionItemsContainerProps.ts b/src/components/ActionItems/ActionItemsContainerProps.ts new file mode 100644 index 0000000000..19ba6f6369 --- /dev/null +++ b/src/components/ActionItems/ActionItemsContainerProps.ts @@ -0,0 +1,131 @@ +type ActionItemsConnectionType = 'Organization' | 'Event'; + +export const props = { + actionItemsConnection: 'Organization' as ActionItemsConnectionType, + actionItemsData: [ + { + _id: 'actionItem1', + assignee: { + _id: 'user1', + firstName: 'Harve', + lastName: 'Lance', + }, + actionItemCategory: { + _id: 'actionItemCategory1', + name: 'ActionItemCategory 1', + }, + preCompletionNotes: 'Pre Completion Notes', + postCompletionNotes: 'Post Completion Notes', + assignmentDate: new Date('2024-02-14'), + dueDate: new Date('2024-02-21'), + completionDate: new Date('2024-02-21'), + isCompleted: false, + assigner: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + event: { + _id: 'event1', + title: 'event 1', + }, + creator: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + { + _id: 'actionItem2', + assignee: { + _id: 'user1', + firstName: 'Harve', + lastName: 'Lance', + }, + actionItemCategory: { + _id: 'actionItemCategory1', + name: 'ActionItemCategory 1', + }, + preCompletionNotes: 'Pre Completion Notes', + postCompletionNotes: 'Post Completion Notes', + assignmentDate: new Date('2024-02-14'), + dueDate: new Date('2024-02-21'), + completionDate: new Date('2024-02-21'), + isCompleted: true, + assigner: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + event: { + _id: 'event1', + title: 'event 1', + }, + creator: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + { + _id: 'actionItem3', + assignee: { + _id: 'user1', + firstName: 'Harve', + lastName: 'Lance', + }, + actionItemCategory: { + _id: 'actionItemCategory1', + name: 'ActionItemCategory 1', + }, + preCompletionNotes: 'Pre Completion Notes more than 25 characters', + postCompletionNotes: 'Post Completion Notes more than 25 characters', + assignmentDate: new Date('2024-02-14'), + dueDate: new Date('2024-02-21'), + completionDate: new Date('2024-02-21'), + isCompleted: true, + assigner: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + event: { + _id: 'event1', + title: 'event 1', + }, + creator: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + ], + membersData: [ + { + _id: 'user1', + firstName: 'Harve', + lastName: 'Lance', + email: 'harve@example.com', + image: '', + organizationsBlockedBy: [], + createdAt: '2024-02-14', + }, + { + _id: 'user2', + firstName: 'Scott', + lastName: 'Norris', + email: 'scott@example.com', + image: '', + organizationsBlockedBy: [], + createdAt: '2024-02-14', + }, + ], + actionItemsRefetch: jest.fn(), +}; + +export const props2 = { + actionItemsConnection: 'Organization' as ActionItemsConnectionType, + actionItemsData: [], + membersData: [], + actionItemsRefetch: jest.fn(), +}; diff --git a/src/components/ActionItems/ActionItemsModal.test.tsx b/src/components/ActionItems/ActionItemsModal.test.tsx new file mode 100644 index 0000000000..01a15ee6aa --- /dev/null +++ b/src/components/ActionItems/ActionItemsModal.test.tsx @@ -0,0 +1,294 @@ +import React from 'react'; +import { + act, + fireEvent, + render, + screen, + waitFor, +} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { MockedProvider } from '@apollo/react-testing'; +import { ActionItemsModal } from './ActionItemsModal'; +import { BrowserRouter } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import { I18nextProvider } from 'react-i18next'; +import i18nForTest from 'utils/i18nForTest'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { toast } from 'react-toastify'; + +import { + MOCKS_ERROR_ACTION_ITEM_CATEGORY_LIST_QUERY, + MOCKS_ERROR_ACTION_ITEM_LIST_QUERY, + MOCKS_ERROR_MEMBERS_LIST_QUERY, + MOCKS_ERROR_MUTATIONS, +} from '../../screens/OrganizationActionItems/OrganizationActionItemsErrorMocks'; +import { MOCKS } from '../../screens/OrganizationActionItems/OrganizationActionItemMocks'; +import { StaticMockLink } from 'utils/StaticMockLink'; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +jest.mock('@mui/x-date-pickers/DateTimePicker', () => { + return { + DateTimePicker: jest.requireActual( + '@mui/x-date-pickers/DesktopDateTimePicker', + ).DesktopDateTimePicker, + }; +}); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink( + MOCKS_ERROR_ACTION_ITEM_CATEGORY_LIST_QUERY, + true, +); +const link3 = new StaticMockLink(MOCKS_ERROR_MEMBERS_LIST_QUERY, true); +const link4 = new StaticMockLink(MOCKS_ERROR_ACTION_ITEM_LIST_QUERY, true); +const link5 = new StaticMockLink(MOCKS_ERROR_MUTATIONS, true); + +const translations = JSON.parse( + JSON.stringify( + i18nForTest.getDataByLanguage('en')?.translation.organizationActionItems, + ), +); + +describe('Testing Check In Attendees Modal', () => { + const formData = { + actionItemCategory: 'ActionItemCategory 1', + assignee: 'Harve Lance', + preCompletionNotes: 'pre completion notes', + dueDate: '02/14/2024', + }; + + const props = { + show: true, + eventId: 'event1', + orgId: '123', + handleClose: jest.fn(), + }; + + test('The modal should be rendered properly', async () => { + render( + + + + + + + + + + + , + ); + + await waitFor(() => + expect(screen.queryByTestId('modal-title')).toBeInTheDocument(), + ); + + await waitFor(() => { + return expect( + screen.findByTestId('createEventActionItemBtn'), + ).resolves.toBeInTheDocument(); + }); + }); + + test('render error component on unsuccessful action item category list query', async () => { + const { queryByText } = render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(queryByText('createEventActionItemBtn')).not.toBeInTheDocument(); + }); + }); + + test('render error component on unsuccessful member list query', async () => { + const { queryByText } = render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(queryByText('createEventActionItemBtn')).not.toBeInTheDocument(); + }); + }); + + test('render error component on unsuccessful action items list query', async () => { + const { queryByText } = render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(queryByText('createEventActionItemBtn')).not.toBeInTheDocument(); + }); + }); + + test('creates new action item associated with the event', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getByTestId('createEventActionItemBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('createEventActionItemBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('createActionItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + await waitFor(() => { + expect( + screen.getByTestId('formSelectActionItemCategory'), + ).toBeInTheDocument(); + }); + + userEvent.selectOptions( + screen.getByTestId('formSelectActionItemCategory'), + formData.actionItemCategory, + ); + + userEvent.selectOptions( + screen.getByTestId('formSelectAssignee'), + formData.assignee, + ); + + userEvent.type( + screen.getByPlaceholderText(translations.preCompletionNotes), + formData.preCompletionNotes, + ); + + const dueDatePicker = screen.getByLabelText(translations.dueDate); + fireEvent.change(dueDatePicker, { + target: { value: formData.dueDate }, + }); + + userEvent.click(screen.getByTestId('createActionItemFormSubmitBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.successfulCreation); + }); + }); + + test('toasts error on unsuccessful creation', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getByTestId('createEventActionItemBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('createEventActionItemBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('createActionItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + await waitFor(() => { + expect( + screen.getByTestId('formSelectActionItemCategory'), + ).toBeInTheDocument(); + }); + + userEvent.selectOptions( + screen.getByTestId('formSelectActionItemCategory'), + formData.actionItemCategory, + ); + + userEvent.selectOptions( + screen.getByTestId('formSelectAssignee'), + formData.assignee, + ); + + userEvent.type( + screen.getByPlaceholderText(translations.preCompletionNotes), + formData.preCompletionNotes, + ); + + const dueDatePicker = screen.getByLabelText(translations.dueDate); + fireEvent.change(dueDatePicker, { + target: { value: formData.dueDate }, + }); + + userEvent.click(screen.getByTestId('createActionItemFormSubmitBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/components/ActionItems/ActionItemsModal.tsx b/src/components/ActionItems/ActionItemsModal.tsx new file mode 100644 index 0000000000..8b8cafba4a --- /dev/null +++ b/src/components/ActionItems/ActionItemsModal.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { Modal } from 'react-bootstrap'; +import styles from 'components/ActionItems/ActionItemsWrapper.module.css'; +import { ActionItemsModalBody } from './ActionItemsModalBody'; +import { useTranslation } from 'react-i18next'; + +export interface InterfaceModalProp { + show: boolean; + eventId: string; + orgId: string; + handleClose: () => void; +} + +export const ActionItemsModal = (props: InterfaceModalProp): JSX.Element => { + const { t } = useTranslation('translation', { + keyPrefix: 'organizationActionItems', + }); + + return ( + <> + + + + {t('eventActionItems')} + + + + + + + + ); +}; diff --git a/src/components/ActionItems/ActionItemsModalBody.tsx b/src/components/ActionItems/ActionItemsModalBody.tsx new file mode 100644 index 0000000000..1aeb536b8b --- /dev/null +++ b/src/components/ActionItems/ActionItemsModalBody.tsx @@ -0,0 +1,218 @@ +import React, { useState } from 'react'; +import type { ChangeEvent } from 'react'; +import { Button } from 'react-bootstrap'; +import { useMutation, useQuery } from '@apollo/client'; +import { + ACTION_ITEM_CATEGORY_LIST, + ACTION_ITEM_LIST, + MEMBERS_LIST, +} from 'GraphQl/Queries/Queries'; +import styles from 'components/ActionItems/ActionItemsWrapper.module.css'; +import type { + InterfaceActionItemCategoryList, + InterfaceActionItemList, + InterfaceMembersList, +} from 'utils/interfaces'; + +import ActionItemsContainer from 'components/ActionItems/ActionItemsContainer'; +import Loader from 'components/Loader/Loader'; +import { WarningAmberRounded } from '@mui/icons-material'; +import { CREATE_ACTION_ITEM_MUTATION } from 'GraphQl/Mutations/ActionItemMutations'; +import dayjs from 'dayjs'; +import { toast } from 'react-toastify'; +import ActionItemCreateModal from 'screens/OrganizationActionItems/ActionItemCreateModal'; +import { useTranslation } from 'react-i18next'; + +export const ActionItemsModalBody = ({ + organizationId, + eventId, +}: { + organizationId: string; + eventId: string; +}): JSX.Element => { + const { t } = useTranslation('translation', { + keyPrefix: 'organizationActionItems', + }); + const { t: tCommon } = useTranslation('common'); + + const [dueDate, setDueDate] = useState(new Date()); + const [actionItemCreateModalIsOpen, setActionItemCreateModalIsOpen] = + useState(false); + + const [formState, setFormState] = useState({ + actionItemCategoryId: '', + assigneeId: '', + preCompletionNotes: '', + }); + + const { + data: actionItemCategoriesData, + loading: actionItemCategoriesLoading, + error: actionItemCategoriesError, + }: { + data: InterfaceActionItemCategoryList | undefined; + loading: boolean; + error?: Error | undefined; + } = useQuery(ACTION_ITEM_CATEGORY_LIST, { + variables: { + organizationId, + }, + notifyOnNetworkStatusChange: true, + }); + + const { + data: membersData, + loading: membersLoading, + error: membersError, + }: { + data: InterfaceMembersList | undefined; + loading: boolean; + error?: Error | undefined; + } = useQuery(MEMBERS_LIST, { + variables: { id: organizationId }, + }); + + const { + data: actionItemsData, + loading: actionItemsLoading, + error: actionItemsError, + refetch: actionItemsRefetch, + }: { + data: InterfaceActionItemList | undefined; + loading: boolean; + error?: Error | undefined; + refetch: () => void; + } = useQuery(ACTION_ITEM_LIST, { + variables: { + organizationId, + eventId, + orderBy: 'createdAt_DESC', + }, + notifyOnNetworkStatusChange: true, + }); + + const [createActionItem] = useMutation(CREATE_ACTION_ITEM_MUTATION); + + const createActionItemHandler = async ( + e: ChangeEvent, + ): Promise => { + e.preventDefault(); + try { + await createActionItem({ + variables: { + assigneeId: formState.assigneeId, + actionItemCategoryId: formState.actionItemCategoryId, + eventId, + preCompletionNotes: formState.preCompletionNotes, + dueDate: dayjs(dueDate).format('YYYY-MM-DD'), + }, + }); + + setFormState({ + assigneeId: '', + actionItemCategoryId: '', + preCompletionNotes: '', + }); + + setDueDate(new Date()); + + actionItemsRefetch(); + hideCreateModal(); + toast.success(t('successfulCreation')); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + console.log(error.message); + } + } + }; + + const showCreateModal = (): void => { + setActionItemCreateModalIsOpen(!actionItemCreateModalIsOpen); + }; + + const hideCreateModal = (): void => { + setActionItemCreateModalIsOpen(!actionItemCreateModalIsOpen); + }; + + if (actionItemCategoriesLoading || membersLoading || actionItemsLoading) { + return ; + } + + if (actionItemCategoriesError || membersError || actionItemsError) { + return ( +
+ +
+ Error occured while loading{' '} + {actionItemCategoriesError + ? 'Action Item Categories' + : membersError + ? 'Members List' + : 'Action Items List'}{' '} + Data +
+ {actionItemCategoriesError + ? actionItemCategoriesError.message + : membersError + ? membersError.message + : actionItemsError?.message} +
+
+ ); + } + + const actionItemCategories = + actionItemCategoriesData?.actionItemCategoriesByOrganization.filter( + (category) => !category.isDisabled, + ); + + const completedActionItemsCount = + actionItemsData?.actionItemsByOrganization.reduce( + (acc, item) => (item.isCompleted === true ? acc + 1 : acc), + 0, + ); + + return ( + <> +
+ + Status: + {actionItemsData?.actionItemsByOrganization.length} action items + assigned, {completedActionItemsCount} completed + + + +
+ + + + {/* Create Modal */} + + + ); +}; diff --git a/src/components/ActionItems/ActionItemsWrapper.module.css b/src/components/ActionItems/ActionItemsWrapper.module.css new file mode 100644 index 0000000000..125db8a125 --- /dev/null +++ b/src/components/ActionItems/ActionItemsWrapper.module.css @@ -0,0 +1,53 @@ +.actionItemsModal { + margin: auto; + max-width: 85%; +} + +button .iconWrapper { + width: 32px; + padding-right: 4px; + margin-right: 4px; +} + +button .iconWrapperSm { + width: 32px; + display: flex; + justify-content: center; + align-items: center; +} + +.errorIcon { + transform: scale(1.5); + color: var(--bs-danger); + margin-bottom: 1rem; +} + +.greenregbtn { + margin: 1rem 0 0; + margin-top: 0; + margin-right: 4px; + border: 1px solid var(--bs-gray-300); + box-shadow: 0 2px 2px var(--bs-gray-300); + padding: 10px 10px; + border-radius: 5px; + background-color: var(--bs-primary); + width: 100%; + font-size: 16px; + color: var(--bs-white); + outline: none; + font-weight: 600; + cursor: pointer; + transition: + transform 0.2s, + box-shadow 0.2s; + max-width: 100px; +} + +.message { + margin-top: 15%; + margin-bottom: 15%; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} diff --git a/src/components/ActionItems/ActionItemsWrapper.test.tsx b/src/components/ActionItems/ActionItemsWrapper.test.tsx new file mode 100644 index 0000000000..7b27e7ccd3 --- /dev/null +++ b/src/components/ActionItems/ActionItemsWrapper.test.tsx @@ -0,0 +1,73 @@ +import React from 'react'; +import { act, render, screen, waitFor } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { ActionItemsWrapper } from './ActionItemsWrapper'; +import { BrowserRouter } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import { I18nextProvider } from 'react-i18next'; +import i18nForTest from 'utils/i18nForTest'; +import { ToastContainer } from 'react-toastify'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import userEvent from '@testing-library/user-event'; +import { MOCKS } from '../../screens/OrganizationActionItems/OrganizationActionItemMocks'; + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const link = new StaticMockLink(MOCKS, true); + +describe('Testing Action Items Wrapper', () => { + const props = { + eventId: 'event1', + orgId: '123', + }; + + test('The button to open and close the modal should work properly', async () => { + render( + + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getByLabelText('eventDashboardActionItems'), + ).toBeInTheDocument(); + }); + + userEvent.click(screen.getByLabelText('eventDashboardActionItems')); + + await waitFor(() => + expect(screen.queryByTestId('modal-title')).toBeInTheDocument(), + ); + + await waitFor(() => { + expect(screen.getByLabelText('Close')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByLabelText('Close')); + + await waitFor(() => + expect(screen.queryByTestId('modal-title')).not.toBeInTheDocument(), + ); + }); +}); diff --git a/src/components/ActionItems/ActionItemsWrapper.tsx b/src/components/ActionItems/ActionItemsWrapper.tsx new file mode 100644 index 0000000000..b44e0782b2 --- /dev/null +++ b/src/components/ActionItems/ActionItemsWrapper.tsx @@ -0,0 +1,45 @@ +import React, { useState } from 'react'; +import { ActionItemsModal } from './ActionItemsModal'; +import { Button } from 'react-bootstrap'; +import IconComponent from 'components/IconComponent/IconComponent'; +import styles from './ActionItemsWrapper.module.css'; +import { useTranslation } from 'react-i18next'; + +type PropType = { + orgId: string; + eventId: string; +}; + +export const ActionItemsWrapper = (props: PropType): JSX.Element => { + const { t } = useTranslation('translation', { + keyPrefix: 'organizationActionItems', + }); + + const [showModal, setShowModal] = useState(false); + + return ( + <> + + {showModal && ( + setShowModal(false)} + orgId={props.orgId} + eventId={props.eventId} + /> + )} + + ); +}; diff --git a/src/components/AddOn/AddOn.module.css b/src/components/AddOn/AddOn.module.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/components/AddOn/AddOn.test.tsx b/src/components/AddOn/AddOn.test.tsx new file mode 100644 index 0000000000..8313fefcb1 --- /dev/null +++ b/src/components/AddOn/AddOn.test.tsx @@ -0,0 +1,34 @@ +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 { 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', () => { + const props = { + children: 'This is a dummy text', + }; + + test('should render props and text elements test for the page component', () => { + const { getByTestId, getByText } = render( + + + + + + + + + , + ); + + expect(getByTestId('pluginContainer')).toBeInTheDocument(); + expect(getByText(props.children)).toBeInTheDocument(); + }); +}); diff --git a/src/components/AddOn/AddOn.tsx b/src/components/AddOn/AddOn.tsx new file mode 100644 index 0000000000..4e73c52b7c --- /dev/null +++ b/src/components/AddOn/AddOn.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +interface InterfaceAddOnProps { + extras: any; + name: string; + children: any; +} + +// Validate Extras +function addOn({ children }: InterfaceAddOnProps): JSX.Element { + return ( + <> +
+ {children} +
+ + ); +} + +addOn.defaultProps = { + extras: {}, + name: '', + children: null, +}; + +addOn.propTypes = { + extras: PropTypes.shape({ + components: PropTypes.shape({}), + actions: PropTypes.shape({}), + }), + name: PropTypes.string, + children: PropTypes.any, +}; + +export default addOn; diff --git a/src/components/AddOn/core/AddOnEntry/AddOnEntry.module.css b/src/components/AddOn/core/AddOnEntry/AddOnEntry.module.css new file mode 100644 index 0000000000..1f1ea89996 --- /dev/null +++ b/src/components/AddOn/core/AddOnEntry/AddOnEntry.module.css @@ -0,0 +1,20 @@ +.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.test.tsx new file mode 100644 index 0000000000..c09840a8f0 --- /dev/null +++ b/src/components/AddOn/core/AddOnEntry/AddOnEntry.test.tsx @@ -0,0 +1,209 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { BrowserRouter } from 'react-router-dom'; +import AddOnEntry from './AddOnEntry'; +import { + ApolloClient, + ApolloProvider, + InMemoryCache, + ApolloLink, + HttpLink, +} from '@apollo/client'; + +import type { NormalizedCacheObject } from '@apollo/client'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import { BACKEND_URL } from 'Constant/constant'; +import i18nForTest from 'utils/i18nForTest'; +import { I18nextProvider } from 'react-i18next'; +import userEvent from '@testing-library/user-event'; +import { MockedProvider, wait } from '@apollo/react-testing'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { ADD_ON_ENTRY_MOCK } from './AddOnEntryMocks'; +import { ToastContainer } from 'react-toastify'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { getItem } = useLocalStorage(); + +const link = new StaticMockLink(ADD_ON_ENTRY_MOCK, true); + +const httpLink = new HttpLink({ + uri: BACKEND_URL, + headers: { + authorization: 'Bearer ' + getItem('token') || '', + }, +}); +console.error = jest.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'), + useParams: () => ({ orgId: mockID }), +})); + +describe('Testing AddOnEntry', () => { + const props = { + id: 'string', + enabled: true, + title: 'string', + description: 'string', + createdBy: 'string', + component: 'string', + installed: true, + configurable: true, + modified: true, + isInstalled: true, + getInstalledPlugins: (): { sample: string } => { + return { sample: 'sample' }; + }, + }; + + test('should render modal and take info to add plugin for registered organization', () => { + const { getByTestId } = render( + + + + + {} + + + + , + ); + expect(getByTestId('AddOnEntry')).toBeInTheDocument(); + }); + + it('renders correctly', () => { + const props = { + id: '1', + title: 'Test Addon', + description: 'Test addon description', + createdBy: 'Test User', + component: 'string', + installed: true, + configurable: true, + modified: true, + isInstalled: true, + uninstalledOrgs: [], + enabled: true, + getInstalledPlugins: (): { sample: string } => { + return { sample: 'sample' }; + }, + }; + + const { getByText } = render( + + + + + {} + + + + , + ); + + expect(getByText('Test Addon')).toBeInTheDocument(); + expect(getByText('Test addon description')).toBeInTheDocument(); + expect(getByText('Test User')).toBeInTheDocument(); + }); + it('Uninstall Button works correctly', async () => { + const props = { + id: '1', + title: 'Test Addon', + description: 'Test addon description', + createdBy: 'Test User', + component: 'string', + installed: true, + configurable: true, + modified: true, + isInstalled: true, + uninstalledOrgs: [], + enabled: true, + getInstalledPlugins: (): { sample: string } => { + return { sample: 'sample' }; + }, + }; + mockID = 'undefined'; + const { findByText, getByTestId } = render( + + + + + + {} + + + + , + ); + await wait(100); + const btn = 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); + + expect(btn.innerHTML).toMatch(/Uninstall/i); + expect( + await findByText('This feature is now enabled in your organization'), + ).toBeInTheDocument(); + }); + + it('Check if uninstalled orgs includes current org', async () => { + const props = { + id: '1', + title: 'Test Addon', + description: 'Test addon description', + createdBy: 'Test User', + component: 'string', + installed: true, + configurable: true, + modified: true, + isInstalled: true, + uninstalledOrgs: ['undefined'], + enabled: true, + getInstalledPlugins: (): { sample: string } => { + return { sample: 'sample' }; + }, + }; + + const { getByTestId } = render( + + + + + {} + + + + , + ); + await wait(100); + const btn = getByTestId('AddOnEntry_btn_install'); + expect(btn.innerHTML).toMatch(/install/i); + }); + test('should be redirected 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 new file mode 100644 index 0000000000..6f2cdaf1dc --- /dev/null +++ b/src/components/AddOn/core/AddOnEntry/AddOnEntry.tsx @@ -0,0 +1,129 @@ +import React, { useState } from 'react'; +import PropTypes from 'prop-types'; +import styles from './AddOnEntry.module.css'; +import { Button, Card, Spinner } from 'react-bootstrap'; +import { UPDATE_INSTALL_STATUS_PLUGIN_MUTATION } from 'GraphQl/Mutations/mutations'; +import { useMutation } from '@apollo/client'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; +import { Navigate, useParams } from 'react-router-dom'; + +interface InterfaceAddOnEntryProps { + id: string; + enabled: boolean; + title: string; + description: string; + createdBy: string; + component: string; + modified: any; + uninstalledOrgs: string[]; + getInstalledPlugins: () => any; +} + +function addOnEntry({ + id, + title, + description, + createdBy, + uninstalledOrgs, + getInstalledPlugins, +}: InterfaceAddOnEntryProps): JSX.Element { + const { t } = useTranslation('translation', { keyPrefix: 'addOnEntry' }); + //getting orgId from URL + const { orgId: currentOrg } = useParams(); + if (!currentOrg) { + return ; + } + const [buttonLoading, setButtonLoading] = useState(false); + const [isInstalledLocal, setIsInstalledLocal] = useState( + uninstalledOrgs.includes(currentOrg), + ); + // const [addOrgAsUninstalled] = useMutation(UPDATE_ORG_STATUS_PLUGIN_MUTATION); + const [addOrgAsUninstalled] = useMutation( + UPDATE_INSTALL_STATUS_PLUGIN_MUTATION, + ); + + const togglePluginInstall = async (): Promise => { + setButtonLoading(true); + await addOrgAsUninstalled({ + variables: { + id: id.toString(), + orgId: currentOrg.toString(), + }, + }); + + setIsInstalledLocal(!isInstalledLocal); + setButtonLoading(false); + const dialog: string = isInstalledLocal + ? t('installMsg') + : t('uninstallMsg'); + toast.success(dialog); + }; + + return ( + <> + + {/* {uninstalledOrgs.includes(currentOrg) && ( + {}} + disabled={switchInProgress} + checked={enabled} + /> + )} */} + + {title} + + {createdBy} + + {description} + + + +
+ + ); +} + +addOnEntry.defaultProps = { + enabled: false, + configurable: true, + title: '', + description: '', + isInstalled: false, +}; + +addOnEntry.propTypes = { + enabled: PropTypes.bool, + configurable: PropTypes.bool, + title: PropTypes.string, + description: PropTypes.string, + isInstalled: PropTypes.bool, +}; + +export default addOnEntry; diff --git a/src/components/AddOn/core/AddOnEntry/AddOnEntryMocks.ts b/src/components/AddOn/core/AddOnEntry/AddOnEntryMocks.ts new file mode 100644 index 0000000000..3967a0963a --- /dev/null +++ b/src/components/AddOn/core/AddOnEntry/AddOnEntryMocks.ts @@ -0,0 +1,25 @@ +import { UPDATE_INSTALL_STATUS_PLUGIN_MUTATION } from 'GraphQl/Mutations/mutations'; + +// Mock data representing the response structure of the mutation +const updatePluginStatus = { + _id: '123', + pluginName: 'Sample Plugin', + pluginCreatedBy: 'John Doe', + pluginDesc: 'This is a sample plugin description.', + uninstalledOrgs: [], +}; + +// Creating the mock entry +export const ADD_ON_ENTRY_MOCK = [ + { + request: { + query: UPDATE_INSTALL_STATUS_PLUGIN_MUTATION, + variables: { id: '1', orgId: 'undefined' }, + }, + result: { + data: { + updatePluginStatus: updatePluginStatus, + }, + }, + }, +]; diff --git a/src/components/AddOn/core/AddOnRegister/AddOnRegister.module.css b/src/components/AddOn/core/AddOnRegister/AddOnRegister.module.css new file mode 100644 index 0000000000..c122d386fa --- /dev/null +++ b/src/components/AddOn/core/AddOnRegister/AddOnRegister.module.css @@ -0,0 +1,9 @@ +.modalbtn { + display: flex !important; + margin-left: auto; + align-items: center; +} + +.modalbtn i { + margin-right: 8px; +} diff --git a/src/components/AddOn/core/AddOnRegister/AddOnRegister.test.tsx b/src/components/AddOn/core/AddOnRegister/AddOnRegister.test.tsx new file mode 100644 index 0000000000..6df580aa76 --- /dev/null +++ b/src/components/AddOn/core/AddOnRegister/AddOnRegister.test.tsx @@ -0,0 +1,201 @@ +import React from 'react'; +import { act, render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { MockedProvider } from '@apollo/react-testing'; +import { ADD_PLUGIN_MUTATION } from 'GraphQl/Mutations/mutations'; +import AddOnRegister from './AddOnRegister'; +import { + ApolloClient, + ApolloProvider, + InMemoryCache, + ApolloLink, + HttpLink, +} from '@apollo/client'; +import type { NormalizedCacheObject } from '@apollo/client'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import { BrowserRouter } from 'react-router-dom'; +import { BACKEND_URL } from 'Constant/constant'; +import i18nForTest from 'utils/i18nForTest'; +import { I18nextProvider } from 'react-i18next'; +import { toast } from 'react-toastify'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { getItem } = useLocalStorage(); + +const httpLink = new HttpLink({ + uri: BACKEND_URL, + headers: { + authorization: 'Bearer ' + getItem('token') || '', + }, +}); + +const client: ApolloClient = new ApolloClient({ + cache: new InMemoryCache(), + link: ApolloLink.from([httpLink]), +}); + +const mocks = [ + { + request: { + query: ADD_PLUGIN_MUTATION, + variables: { + pluginName: 'Test Plugin', + pluginCreatedBy: 'Test Creator', + pluginDesc: 'Test Description', + pluginInstallStatus: false, + installedOrgs: ['id'], + }, + }, + result: { + data: { + createPlugin: { + _id: '1', + pluginName: 'Test Plugin', + pluginCreatedBy: 'Test Creator', + pluginDesc: 'Test Description', + }, + }, + }, + }, +]; + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const pluginData = { + pluginName: 'Test Plugin', + pluginCreatedBy: 'Test Creator', + pluginDesc: 'Test Description', +}; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + }, +})); + +const mockNavigate = jest.fn(); +let mockId: string | undefined = 'id'; +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + 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 () => { + await act(async () => { + render( + + + + + {} + + + + , + ); + + await wait(100); + + userEvent.click(screen.getByRole('button', { name: /Add New/i })); + userEvent.type(screen.getByPlaceholderText(/Ex: Donations/i), 'myplugin'); + userEvent.type( + screen.getByPlaceholderText(/This Plugin enables UI for/i), + 'test description', + ); + userEvent.type( + screen.getByPlaceholderText(/Ex: john Doe/i), + 'test creator', + ); + }); + }); + + test('Expect toast.success to be called on successful plugin addition', async () => { + await act(async () => { + render( + + + + + + + + + , + ); + await waitFor(() => new Promise((resolve) => setTimeout(resolve, 0))); + + userEvent.click(screen.getByRole('button', { name: /Add New/i })); + await wait(100); + expect(screen.getByTestId('addonregisterBtn')).toBeInTheDocument(); + userEvent.type(screen.getByTestId('pluginName'), pluginData.pluginName); + userEvent.type( + screen.getByTestId('pluginCreatedBy'), + pluginData.pluginCreatedBy, + ); + userEvent.type(screen.getByTestId('pluginDesc'), pluginData.pluginDesc); + userEvent.click(screen.getByTestId('addonregisterBtn')); + + await wait(100); + expect(toast.success).toBeCalledWith('Plugin added Successfully'); + }); + }); + + test('Expect the window to reload after successful plugin addition', async () => { + await act(async () => { + render( + + + + + + + + + , + ); + await waitFor(() => new Promise((resolve) => setTimeout(resolve, 0))); + + userEvent.click(screen.getByRole('button', { name: /Add New/i })); + await wait(100); + expect(screen.getByTestId('addonregisterBtn')).toBeInTheDocument(); + userEvent.type(screen.getByTestId('pluginName'), pluginData.pluginName); + userEvent.type( + screen.getByTestId('pluginCreatedBy'), + pluginData.pluginCreatedBy, + ); + userEvent.type(screen.getByTestId('pluginDesc'), pluginData.pluginDesc); + userEvent.click(screen.getByTestId('addonregisterBtn')); + + await wait(3000); // Waiting for 3 seconds to reload the page as timeout is set to 2 seconds in the component + expect(mockNavigate).toHaveBeenCalledWith(0); + }); + }); + test('should be redirected to /orglist if orgId is undefined', async () => { + mockId = undefined; + render( + + + + + {} + + + + , + ); + expect(window.location.pathname).toEqual('/orglist'); + }); +}); diff --git a/src/components/AddOn/core/AddOnRegister/AddOnRegister.tsx b/src/components/AddOn/core/AddOnRegister/AddOnRegister.tsx new file mode 100644 index 0000000000..059eae5d43 --- /dev/null +++ b/src/components/AddOn/core/AddOnRegister/AddOnRegister.tsx @@ -0,0 +1,161 @@ +import React, { useState } from 'react'; +import PropTypes from 'prop-types'; +import styles from './AddOnRegister.module.css'; +import { Button, Form, Modal } from 'react-bootstrap'; +import { useMutation } from '@apollo/client'; +import { ADD_PLUGIN_MUTATION } from 'GraphQl/Mutations/mutations'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; +import { Navigate, useNavigate, useParams } from 'react-router-dom'; + +interface InterfaceFormStateTypes { + pluginName: string; + pluginCreatedBy: string; + pluginDesc: string; + pluginInstallStatus: boolean; + installedOrgs: [string] | []; +} + +function addOnRegister(): JSX.Element { + const { t } = useTranslation('translation', { keyPrefix: 'addOnRegister' }); + const { t: tCommon } = useTranslation('common'); + + const { orgId: currentUrl } = useParams(); + const navigate = useNavigate(); + if (!currentUrl) { + return ; + } + + const [show, setShow] = useState(false); + + const handleClose = (): void => setShow(false); + const handleShow = (): void => setShow(true); + const [create] = useMutation(ADD_PLUGIN_MUTATION); + + const [formState, setFormState] = useState({ + pluginName: '', + pluginCreatedBy: '', + pluginDesc: '', + pluginInstallStatus: false, + installedOrgs: [currentUrl], + }); + + const handleRegister = async (): Promise => { + const { data } = await create({ + variables: { + pluginName: formState.pluginName, + pluginCreatedBy: formState.pluginCreatedBy, + pluginDesc: formState.pluginDesc, + pluginInstallStatus: formState.pluginInstallStatus, + installedOrgs: formState.installedOrgs, + }, + }); + + if (data) { + toast.success(tCommon('addedSuccessfully', { item: 'Plugin' })); + setTimeout(() => { + navigate(0); + }, 2000); + } + }; + return ( + <> + + + + + {t('addPlugin')} + + +
+ + {t('pluginName')} + { + setFormState({ + ...formState, + pluginName: e.target.value, + }); + }} + /> + + + {t('creatorName')} + { + setFormState({ + ...formState, + pluginCreatedBy: e.target.value, + }); + }} + /> + + + {t('pluginDesc')} + { + setFormState({ + ...formState, + pluginDesc: e.target.value, + }); + }} + /> + +
+
+ + + + +
+ + ); +} + +addOnRegister.defaultProps = { + createdBy: 'Admin', +}; + +addOnRegister.propTypes = { + createdBy: PropTypes.string, +}; + +export default addOnRegister; diff --git a/src/components/AddOn/core/AddOnStore/AddOnStore.module.css b/src/components/AddOn/core/AddOnStore/AddOnStore.module.css new file mode 100644 index 0000000000..8a34c03be5 --- /dev/null +++ b/src/components/AddOn/core/AddOnStore/AddOnStore.module.css @@ -0,0 +1,31 @@ +.container { + display: flex; +} + +.logintitle { + color: #707070; + font-weight: 600; + font-size: 20px; + margin-bottom: 30px; + padding-bottom: 5px; + border-bottom: 3px solid #31bb6b; + width: 15%; +} + +.actioninput { + 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; +} + +.actionradio input { + width: fit-content; + margin: inherit; +} diff --git a/src/components/AddOn/core/AddOnStore/AddOnStore.test.tsx b/src/components/AddOn/core/AddOnStore/AddOnStore.test.tsx new file mode 100644 index 0000000000..600e34dd5d --- /dev/null +++ b/src/components/AddOn/core/AddOnStore/AddOnStore.test.tsx @@ -0,0 +1,394 @@ +import React from 'react'; +import 'jest-location-mock'; +import { act, fireEvent, render, screen } from '@testing-library/react'; +import { + ApolloClient, + ApolloProvider, + InMemoryCache, + ApolloLink, + HttpLink, +} from '@apollo/client'; +import type { NormalizedCacheObject } from '@apollo/client'; +import { BrowserRouter } from 'react-router-dom'; +import AddOnStore from './AddOnStore'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import { BACKEND_URL } from 'Constant/constant'; +import i18nForTest from 'utils/i18nForTest'; +import { I18nextProvider } from 'react-i18next'; +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'; + +const { getItem } = useLocalStorage(); + +jest.mock('components/AddOn/support/services/Plugin.helper', () => ({ + __esModule: true, + default: jest.fn().mockImplementation(() => ({ + fetchStore: jest.fn().mockResolvedValue([ + { + _id: '1', + pluginName: 'Plugin 1', + pluginDesc: 'Description 1', + pluginCreatedBy: 'User 1', + pluginInstallStatus: true, + }, + { + _id: '2', + pluginName: 'Plugin 2', + pluginDesc: 'Description 2', + pluginCreatedBy: 'User 2', + pluginInstallStatus: false, + }, + // Add more mock data as needed + ]), + fetchInstalled: jest.fn().mockResolvedValue([ + { + _id: '1', + pluginName: 'Installed Plugin 1', + pluginDesc: 'Installed Description 1', + pluginCreatedBy: 'User 3', + pluginInstallStatus: true, + }, + { + _id: '3', + pluginName: 'Installed Plugin 3', + pluginDesc: 'Installed Description 3', + pluginCreatedBy: 'User 4', + pluginInstallStatus: true, + }, + // Add more mock data as needed + ]), + generateLinks: jest.fn().mockImplementation((plugins) => { + return plugins + .filter((plugin: { enabled: any }) => plugin.enabled) + .map((installedPlugin: { pluginName: any; component: string }) => { + return { + name: installedPlugin.pluginName, + url: `/plugin/${installedPlugin.component.toLowerCase()}`, + }; + }); + }), + })), +})); + +const httpLink = new HttpLink({ + uri: BACKEND_URL, + headers: { + authorization: 'Bearer ' + getItem('token') || '', + }, +}); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const client: ApolloClient = new ApolloClient({ + cache: new InMemoryCache(), + link: ApolloLink.from([httpLink]), +}); + +jest.mock('components/AddOn/support/services/Plugin.helper', () => ({ + __esModule: true, + default: jest.fn().mockImplementation(() => ({ + fetchInstalled: jest.fn().mockResolvedValue([]), + fetchStore: jest.fn().mockResolvedValue([]), + })), +})); + +const today = new Date(); +const tomorrow = today; +tomorrow.setDate(today.getDate() + 1); + +const PLUGIN_GET_MOCK = { + request: { + query: PLUGIN_GET, + }, + result: { + data: { + getPlugins: [ + { + _id: '6581be50e88e74003aab436c', + pluginName: 'Plugin 1', + pluginCreatedBy: 'Talawa Team', + pluginDesc: + 'User can share messages with other users in a chat user interface.', + uninstalledOrgs: [ + '62ccfccd3eb7fd2a30f41601', + '62ccfccd3eb7fd2a30f41601', + ], + __typename: 'Plugin', + }, + { + _id: '6581be50e88e74003aab436d', + pluginName: 'Plugin 2', + pluginCreatedBy: 'Talawa Team', + pluginDesc: + 'User can share messages with other users in a chat user interface.', + uninstalledOrgs: ['6537904485008f171cf29924'], + __typename: 'Plugin', + }, + { + _id: '6581be50e88e74003aab436e', + pluginName: 'Plugin 3', + pluginCreatedBy: 'Talawa Team', + pluginDesc: + 'User can share messages with other users in a chat user interface.', + uninstalledOrgs: [ + '62ccfccd3eb7fd2a30f41601', + '62ccfccd3eb7fd2a30f41601', + ], + __typename: 'Plugin', + }, + ], + }, + loading: false, + }, +}; + +const PLUGIN_LOADING_MOCK = { + request: { + query: PLUGIN_GET, + }, + result: { + data: { + getPlugins: [], + }, + loading: true, + }, +}; +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: 'undefined' }), +})); +const ORGANIZATIONS_LIST_MOCK = { + request: { + query: ORGANIZATIONS_LIST, + variables: { + id: 'undefined', + }, + }, + result: { + data: { + organizations: [ + { + _id: 'undefined', + image: '', + creator: { + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + name: 'name', + description: 'description', + userRegistrationRequired: true, + + visibleInSearch: true, + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + members: { + _id: 'id', + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + admins: { + _id: 'id', + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + membershipRequests: { + _id: 'id', + user: { + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + }, + blockedUsers: { + _id: 'id', + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + }, + ], + }, + }, +}; + +describe('Testing AddOnStore Component', () => { + test('for the working of the tabs', async () => { + const mocks = [ORGANIZATIONS_LIST_MOCK, PLUGIN_GET_MOCK]; + + render( + + + + + + + + + + + , + ); + + await wait(); + userEvent.click(screen.getByText('Installed')); + + await wait(); + userEvent.click(screen.getByText('Available')); + }); + + test('check the working search bar when on Available tab', async () => { + const mocks = [ORGANIZATIONS_LIST_MOCK, PLUGIN_GET_MOCK]; + + render( + + + + + + + + + + + , + ); + + await wait(); + userEvent.click(screen.getByText('Available')); + + await wait(); + let searchText = ''; + fireEvent.change(screen.getByPlaceholderText('Ex: Donations'), { + target: { value: searchText }, + }); + expect(screen.getAllByText('Plugin 1').length).toBeGreaterThanOrEqual(1); + expect(screen.getAllByText('Plugin 2').length).toBeGreaterThanOrEqual(1); + expect(screen.getAllByText('Plugin 3').length).toBeGreaterThanOrEqual(1); + + 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('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]; + render( + + + + + + + + + + + , + ); + + expect(screen.getByTestId('AddOnEntryStore')).toBeInTheDocument(); + }); +}); diff --git a/src/components/AddOn/core/AddOnStore/AddOnStore.tsx b/src/components/AddOn/core/AddOnStore/AddOnStore.tsx new file mode 100644 index 0000000000..9eb65f9241 --- /dev/null +++ b/src/components/AddOn/core/AddOnStore/AddOnStore.tsx @@ -0,0 +1,303 @@ +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'; // PLUGIN_LIST +import { Col, Form, Row, Tab, Tabs } 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'; + +function addOnStore(): JSX.Element { + const { t } = useTranslation('translation', { keyPrefix: 'addOnStore' }); + document.title = t('title'); + + const [isStore, setIsStore] = useState(true); + const [showEnabled, setShowEnabled] = useState(true); + const [searchText, setSearchText] = useState(''); + const [, setDataList] = useState([]); + + // type plugData = { pluginName: String, plug }; + const { data, loading } = useQuery(PLUGIN_GET); + + const { orgId } = useParams(); + + /* istanbul ignore next */ + const getStorePlugins = async (): Promise => { + let plugins = await new PluginHelper().fetchStore(); + const installIds = (await new PluginHelper().fetchInstalled()).map( + (plugin: any) => plugin.id, + ); + plugins = plugins.map((plugin: any) => { + plugin.installed = installIds.includes(plugin.id); + return plugin; + }); + store.dispatch({ type: 'UPDATE_STORE', payload: plugins }); + }; + + /* istanbul ignore next */ + const getInstalledPlugins: () => any = () => { + setDataList(data); + // setRender((current) => !current); + // const { + // data: newData, + // loading: newLoading, + // error: newError, + // } = useQuery(PLUGIN_GET); + // data = newData; + // loading = newLoading; + // error = newError; + // const plugins = await new PluginHelper().fetchInstalled(); + // store.dispatch({ type: 'UPDATE_INSTALLED', payload: plugins }); + // return plugins; + }; + + const updateSelectedTab = (tab: any): void => { + setIsStore(tab === 'available'); + /* istanbul ignore next */ + isStore ? getStorePlugins() : getInstalledPlugins(); + }; + + const filterChange = (ev: any): void => { + setShowEnabled(ev.target.value === 'enabled'); + }; + + /* istanbul ignore next */ + if (loading) { + return ( + <> +
+ + ); + } + return ( + <> + + + + setSearchText(e.target.value)} + /> + + {!isStore && ( + +
+
+ + +
+
+
+ )} + + +
+

{t('pHeading')}

+ {searchText ? ( +

+ Search results for {searchText} +

+ ) : null} + + + + {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 => ( + + ), + ) + )} +
+
+
+ +
+ + ); +} + +addOnStore.defaultProps = {}; + +addOnStore.propTypes = {}; + +export default addOnStore; diff --git a/src/components/AddOn/support/components/Action/Action.module.css b/src/components/AddOn/support/components/Action/Action.module.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/components/AddOn/support/components/Action/Action.test.tsx b/src/components/AddOn/support/components/Action/Action.test.tsx new file mode 100644 index 0000000000..ce6cd633b9 --- /dev/null +++ b/src/components/AddOn/support/components/Action/Action.test.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { Provider } from 'react-redux'; + +import { store } from 'state/store'; +import Action from './Action'; + +describe('Testing Action Component', () => { + const props = { + children: 'dummy children', + label: 'dummy label', + }; + + test('should render props and text elements test for the page component', () => { + const { getByText } = render( + + + , + ); + + expect(getByText(props.label)).toBeInTheDocument(); + expect(getByText(props.children)).toBeInTheDocument(); + }); +}); diff --git a/src/components/AddOn/support/components/Action/Action.tsx b/src/components/AddOn/support/components/Action/Action.tsx new file mode 100644 index 0000000000..50b6b10797 --- /dev/null +++ b/src/components/AddOn/support/components/Action/Action.tsx @@ -0,0 +1,21 @@ +import React, { useRef } from 'react'; + +// TODO: UI logic for embedded actions (hide label) +interface InterfaceActionProps { + children: any; + label: string; +} + +// TODO: props => Validate child element type, register functions from children for global use?, +function action(props: InterfaceActionProps): JSX.Element { + const actionRef = useRef(null); + + return ( +
+
{props.label}
+ {props.children} +
+ ); +} + +export default action; diff --git a/src/components/AddOn/support/components/MainContent/MainContent.module.css b/src/components/AddOn/support/components/MainContent/MainContent.module.css new file mode 100644 index 0000000000..3321cf6fd7 --- /dev/null +++ b/src/components/AddOn/support/components/MainContent/MainContent.module.css @@ -0,0 +1,4 @@ +.maincontainer { + width: 70vw; + margin-right: 2rem; +} diff --git a/src/components/AddOn/support/components/MainContent/MainContent.test.tsx b/src/components/AddOn/support/components/MainContent/MainContent.test.tsx new file mode 100644 index 0000000000..81adbc916e --- /dev/null +++ b/src/components/AddOn/support/components/MainContent/MainContent.test.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; + +import { store } from 'state/store'; +import MainContent from './MainContent'; + +describe('Testing MainContent component', () => { + const props = { + children: 'This is a dummy text', + }; + + test('should render props and children for the Main Content', () => { + const { getByTestId, getByText } = render( + + + + + , + ); + + expect(getByTestId('mainContentCheck')).toBeInTheDocument(); + expect(getByText(props.children)).toBeInTheDocument(); + }); +}); diff --git a/src/components/AddOn/support/components/MainContent/MainContent.tsx b/src/components/AddOn/support/components/MainContent/MainContent.tsx new file mode 100644 index 0000000000..7ca4dfc8c4 --- /dev/null +++ b/src/components/AddOn/support/components/MainContent/MainContent.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import styles from './MainContent.module.css'; +interface InterfaceMainContentProps { + children: any; +} + +// TODO: Implement extras plugins +// TODO: Implement additional styles +// id - [plugin/component-name]-main-content if is in plugin +function mainContent({ children }: InterfaceMainContentProps): JSX.Element { + return ( +
+ {children} +
+ ); +} + +export default mainContent; diff --git a/src/components/AddOn/support/components/SidePanel/SidePanel.module.css b/src/components/AddOn/support/components/SidePanel/SidePanel.module.css new file mode 100644 index 0000000000..f337eeea1b --- /dev/null +++ b/src/components/AddOn/support/components/SidePanel/SidePanel.module.css @@ -0,0 +1,12 @@ +.sidebarcontainer { + width: 30vw; + justify-content: center; + display: flex; + flex-direction: column; + padding: 2rem; + height: fit-content; +} + +.sidebarcollapsed { + display: none; +} diff --git a/src/components/AddOn/support/components/SidePanel/SidePanel.test.tsx b/src/components/AddOn/support/components/SidePanel/SidePanel.test.tsx new file mode 100644 index 0000000000..d929278d0e --- /dev/null +++ b/src/components/AddOn/support/components/SidePanel/SidePanel.test.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import SidePanel from './SidePanel'; +import type { NormalizedCacheObject } from '@apollo/client'; +import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client'; +import { BACKEND_URL } from 'Constant/constant'; + +const client: ApolloClient = new ApolloClient({ + cache: new InMemoryCache(), + uri: BACKEND_URL, +}); + +describe('Testing Contribution Stats', () => { + const props = { + collapse: true, + children: '234', + }; + + test('should render props and text elements test for the SidePanel component', () => { + render( + + + , + ); + expect(screen.getByTestId('SidePanel')).toBeInTheDocument(); + }); +}); diff --git a/src/components/AddOn/support/components/SidePanel/SidePanel.tsx b/src/components/AddOn/support/components/SidePanel/SidePanel.tsx new file mode 100644 index 0000000000..2eda5e7225 --- /dev/null +++ b/src/components/AddOn/support/components/SidePanel/SidePanel.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import styles from './SidePanel.module.css'; +interface InterfaceSidePanelProps { + collapse?: boolean; + children: any; +} + +// TODO: Implement Extras Plugin +// id - [plugin-name]-side-panel +function sidePanel({ + collapse, + children, +}: InterfaceSidePanelProps): JSX.Element { + return ( +
+ {children} +
+ ); +} + +export default sidePanel; diff --git a/src/components/AddOn/support/services/Plugin.helper.test.ts b/src/components/AddOn/support/services/Plugin.helper.test.ts new file mode 100644 index 0000000000..e024734247 --- /dev/null +++ b/src/components/AddOn/support/services/Plugin.helper.test.ts @@ -0,0 +1,46 @@ +import PluginHelper from './Plugin.helper'; + +describe('Testing src/components/AddOn/support/services/Plugin.helper.ts', () => { + test('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' }; + const objToMatch = { name: 'demo', url: '/plugin/samplecomponent' }; + const pluginHelper = new PluginHelper(); + const val = pluginHelper.generateLinks([obj]); + expect(val).toMatchObject([objToMatch]); + }); + it('fetchStore should return expected JSON', async () => { + const helper = new PluginHelper(); + const spy = jest.spyOn(global, 'fetch').mockImplementation(() => { + const response = new Response(); + response.json = jest + .fn() + .mockReturnValue(Promise.resolve({ data: 'mock data' })); + return Promise.resolve(response); + }); + + const result = await helper.fetchStore(); + expect(result).toEqual({ data: 'mock data' }); + spy.mockRestore(); + }); + it('fetchInstalled() should return expected JSON', async () => { + const pluginHelper = new PluginHelper(); + const mockResponse = [ + { name: 'plugin1', component: 'Component1', enabled: true }, + { name: 'plugin2', component: 'Component2', enabled: false }, + ]; + jest.spyOn(global, 'fetch').mockImplementation(() => { + const response = new Response(); + response.json = jest.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/AddOn/support/services/Plugin.helper.ts b/src/components/AddOn/support/services/Plugin.helper.ts new file mode 100644 index 0000000000..4730f0c568 --- /dev/null +++ b/src/components/AddOn/support/services/Plugin.helper.ts @@ -0,0 +1,24 @@ +class PluginHelper { + fetchStore = async (): Promise => { + const result = await fetch(`http://localhost:${process.env.PORT}/store`); + return await result.json(); + }; + + fetchInstalled = async (): Promise => { + const result = await fetch(`http://localhost:3005/installed`); + return await result.json(); + }; + + generateLinks = (plugins: any[]): { name: string; url: string }[] => { + return plugins + .filter((plugin: any) => plugin.enabled) + .map((installedPlugin: any) => { + return { + name: installedPlugin.name, + url: `/plugin/${installedPlugin.component.toLowerCase()}`, + }; + }); + }; +} + +export default PluginHelper; diff --git a/src/components/AddOn/support/services/Render.helper.ts b/src/components/AddOn/support/services/Render.helper.ts new file mode 100644 index 0000000000..21202dc7af --- /dev/null +++ b/src/components/AddOn/support/services/Render.helper.ts @@ -0,0 +1,3 @@ +class RenderHelper {} + +export default RenderHelper; diff --git a/src/components/Advertisements/Advertisements.module.css b/src/components/Advertisements/Advertisements.module.css new file mode 100644 index 0000000000..8a34c03be5 --- /dev/null +++ b/src/components/Advertisements/Advertisements.module.css @@ -0,0 +1,31 @@ +.container { + display: flex; +} + +.logintitle { + color: #707070; + font-weight: 600; + font-size: 20px; + margin-bottom: 30px; + padding-bottom: 5px; + border-bottom: 3px solid #31bb6b; + width: 15%; +} + +.actioninput { + 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; +} + +.actionradio input { + width: fit-content; + margin: inherit; +} diff --git a/src/components/Advertisements/Advertisements.test.tsx b/src/components/Advertisements/Advertisements.test.tsx new file mode 100644 index 0000000000..b45e1bab38 --- /dev/null +++ b/src/components/Advertisements/Advertisements.test.tsx @@ -0,0 +1,730 @@ +import React from 'react'; +import { + ApolloClient, + ApolloLink, + ApolloProvider, + HttpLink, + InMemoryCache, +} from '@apollo/client'; +import { MockedProvider } from '@apollo/client/testing'; +import { act, 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 { + ORGANIZATIONS_LIST, + ORGANIZATION_ADVERTISEMENT_LIST, + PLUGIN_GET, +} 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 Advertisement from './Advertisements'; + +const { getItem } = useLocalStorage(); + +const httpLink = new HttpLink({ + uri: BACKEND_URL, + headers: { + authorization: 'Bearer ' + getItem('token') || '', + }, +}); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const client: ApolloClient = new ApolloClient({ + cache: new InMemoryCache(), + link: ApolloLink.from([httpLink]), +}); + +jest.mock('components/AddOn/support/services/Plugin.helper', () => ({ + __esModule: true, + default: jest.fn().mockImplementation(() => ({ + fetchInstalled: jest.fn().mockResolvedValue([]), + fetchStore: jest.fn().mockResolvedValue([]), + })), +})); +let mockID: string | undefined = '1'; +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: mockID }), +})); + +const today = new Date(); +const tomorrow = today; +tomorrow.setDate(today.getDate() + 1); + +const ADVERTISEMENTS_LIST_MOCK: { + request: + | { + query: DocumentNode; + variables: { id: string; first: number; after: null }; + } + | { + query: DocumentNode; + variables: { + id: string; + first: number; + after: null; + before: null; + last: null; + }; + }; + result: + | { + data: { + organizations: { + _id: string; + advertisements: { + edges: { + node: { + _id: string; + name: string; + startDate: string; + endDate: string; + mediaUrl: string; + }; + cursor: string; + }[]; + pageInfo: { + startCursor: string; + endCursor: string; + hasNextPage: boolean; + hasPreviousPage: boolean; + }; + totalCount: number; + }; + }[]; + }; + } + | { + data: { + organizations: { + _id: string; + advertisements: { + edges: { + node: { + _id: string; + name: string; + startDate: string; + endDate: string; + mediaUrl: string; + }; + cursor: string; + }[]; + pageInfo: { + startCursor: string; + endCursor: string; + hasNextPage: boolean; + hasPreviousPage: boolean; + }; + totalCount: number; + }; + }[]; + }; + }; +}[] = []; + +for (let i = 0; i < 4; i++) { + ADVERTISEMENTS_LIST_MOCK.push({ + request: { + query: ORGANIZATION_ADVERTISEMENT_LIST, + variables: { + id: '1', + first: 6, + after: null, + }, + }, + result: { + data: { + organizations: [ + { + _id: '1', + advertisements: { + edges: [ + { + node: { + _id: '1', + name: 'Advertisement1', + startDate: '2022-01-01', + endDate: '2023-01-01', + mediaUrl: 'http://example1.com', + }, + cursor: 'cursor1', + }, + { + node: { + _id: '2', + name: 'Advertisement2', + startDate: '2024-02-01', + endDate: '2025-02-01', + mediaUrl: 'http://example2.com', + }, + cursor: 'cursor2', + }, + ], + pageInfo: { + startCursor: 'cursor1', + endCursor: 'cursor2', + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 2, + }, + }, + ], + }, + }, + }); + ADVERTISEMENTS_LIST_MOCK.push({ + request: { + query: ORGANIZATION_ADVERTISEMENT_LIST, + variables: { + id: '1', + first: 6, + after: null, + before: null, + last: null, + }, + }, + result: { + data: { + organizations: [ + { + _id: '1', + advertisements: { + edges: [ + { + node: { + _id: '1', + name: 'Advertisement1', + startDate: '2022-01-01', + endDate: '2023-01-01', + mediaUrl: 'http://example1.com', + }, + cursor: 'cursor1', + }, + { + node: { + _id: '2', + name: 'Advertisement2', + startDate: '2024-02-01', + endDate: '2025-02-01', + mediaUrl: 'http://example2.com', + }, + cursor: 'cursor2', + }, + ], + pageInfo: { + startCursor: 'cursor1', + endCursor: 'cursor2', + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 2, + }, + }, + ], + }, + }, + }); +} + +const PLUGIN_GET_MOCK = { + request: { + query: PLUGIN_GET, + }, + result: { + data: { + getPlugins: [ + { + _id: '6581be50e88e74003aab436c', + pluginName: 'Chats', + pluginCreatedBy: 'Talawa Team', + pluginDesc: + 'User can share messages with other users in a chat user interface.', + uninstalledOrgs: [ + '62ccfccd3eb7fd2a30f41601', + '62ccfccd3eb7fd2a30f41601', + ], + pluginInstallStatus: true, + __typename: 'Plugin', + }, + ], + }, + loading: false, + }, +}; + +const ADD_ADVERTISEMENT_MUTATION_MOCK = { + request: { + query: ADD_ADVERTISEMENT_MUTATION, + variables: { + organizationId: '1', + name: 'Cookie Shop', + file: 'data:image/png;base64,bWVkaWEgY29udGVudA==', + type: 'POPUP', + startDate: '2023-01-01', + endDate: '2023-02-02', + }, + }, + result: { + data: { + createAdvertisement: { + _id: '65844efc814dd4003db811c4', + advertisement: null, + __typename: 'Advertisement', + }, + }, + }, +}; + +const ORGANIZATIONS_LIST_MOCK = { + request: { + query: ORGANIZATIONS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + organizations: [ + { + _id: '1', + image: '', + creator: { + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + name: 'name', + description: 'description', + userRegistrationRequired: true, + + visibleInSearch: true, + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + members: { + _id: 'id', + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + admins: { + _id: 'id', + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + membershipRequests: { + _id: 'id', + user: { + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + }, + blockedUsers: { + _id: 'id', + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + }, + ], + }, + }, +}; + +describe('Testing Advertisement Component', () => { + test('for creating new Advertisements', async () => { + const mocks = [ + ORGANIZATIONS_LIST_MOCK, + PLUGIN_GET_MOCK, + ADD_ADVERTISEMENT_MUTATION_MOCK, + ...ADVERTISEMENTS_LIST_MOCK, + ]; + + render( + + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByText('Create Advertisement')); + userEvent.type( + screen.getByLabelText('Enter name of Advertisement'), + 'Cookie Shop', + ); + const mediaFile = new File(['media content'], 'test.png', { + type: 'image/png', + }); + + const mediaInput = screen.getByTestId('advertisementMedia'); + fireEvent.change(mediaInput, { + target: { + files: [mediaFile], + }, + }); + const mediaPreview = await screen.findByTestId('mediaPreview'); + expect(mediaPreview).toBeInTheDocument(); + userEvent.selectOptions( + screen.getByLabelText('Select type of Advertisement'), + 'POPUP', + ); + userEvent.type(screen.getByLabelText('Select Start Date'), '2023-01-01'); + userEvent.type(screen.getByLabelText('Select End Date'), '2023-02-02'); + + userEvent.click(screen.getByTestId('addonregister')); + expect( + await screen.findByText('Advertisement created successfully.'), + ).toBeInTheDocument(); + }); + + test('for the working of the tabs', async () => { + const mocks = [ + ORGANIZATIONS_LIST_MOCK, + PLUGIN_GET_MOCK, + ADD_ADVERTISEMENT_MUTATION_MOCK, + ...ADVERTISEMENTS_LIST_MOCK, + ]; + + render( + + + + + + + + + + + , + ); + + await wait(); + userEvent.click(screen.getByText('Active Campaigns')); + + await wait(); + userEvent.click(screen.getByText('Completed Campaigns')); + }); + + test('if the component renders correctly and ads are correctly categorized date wise', async () => { + mockID = '1'; + const mocks = [...ADVERTISEMENTS_LIST_MOCK]; + + render( + + + + + + + + + + + , + ); + + await wait(); + + const date = await screen.findAllByTestId('Ad_end_date'); + const dateString = date[1].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); + } + + expect(dateObject.getTime()).toBeLessThan(new Date().getTime()); + }); + + test('delete ad', async () => { + mockID = '1'; + const mocks = [...ADVERTISEMENTS_LIST_MOCK]; + + render( + + + + + + + + + + + , + ); + + await wait(); + + const moreiconbtn = await screen.findAllByTestId('moreiconbtn'); + fireEvent.click(moreiconbtn[1]); + const deleteBtn = await screen.findByTestId('deletebtn'); + expect(deleteBtn).toBeInTheDocument(); + fireEvent.click(deleteBtn); + }); + + test('infinite scroll', async () => { + mockID = '1'; + const mocks = [ + ...ADVERTISEMENTS_LIST_MOCK, + { + request: { + query: ORGANIZATION_ADVERTISEMENT_LIST, + variables: { + id: '1', + first: 2, + after: null, + last: null, + before: null, + }, + }, + result: { + data: { + organizations: [ + { + _id: '1', + advertisements: { + edges: [ + { + node: { + _id: '1', + name: 'Advertisement1', + startDate: '2022-01-01', + endDate: '2023-01-01', + mediaUrl: 'http://example1.com', + }, + cursor: 'cursor1', + }, + { + node: { + _id: '2', + name: 'Advertisement2', + startDate: '2024-02-01', + endDate: '2025-02-01', + mediaUrl: 'http://example2.com', + }, + cursor: 'cursor2', + }, + { + node: { + _id: '3', + name: 'Advertisement1', + startDate: '2022-01-01', + endDate: '2023-01-01', + mediaUrl: 'http://example1.com', + }, + cursor: 'cursor3', + }, + { + node: { + _id: '4', + name: 'Advertisement2', + startDate: '2024-02-01', + endDate: '2025-02-01', + mediaUrl: 'http://example2.com', + }, + cursor: 'cursor4', + }, + { + node: { + _id: '5', + name: 'Advertisement1', + startDate: '2022-01-01', + endDate: '2023-01-01', + mediaUrl: 'http://example1.com', + }, + cursor: 'cursor5', + }, + { + node: { + _id: '6', + name: 'Advertisement2', + startDate: '2024-02-01', + endDate: '2025-02-01', + mediaUrl: 'http://example2.com', + }, + cursor: 'cursor6', + }, + ], + pageInfo: { + startCursor: 'cursor1', + endCursor: 'cursor6', + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 8, + }, + }, + ], + }, + }, + }, + { + request: { + query: ORGANIZATION_ADVERTISEMENT_LIST, + variables: { + id: '1', + first: 6, + after: 'cursor6', + last: null, + before: null, + }, + }, + result: { + data: { + organizations: [ + { + _id: '1', + advertisements: { + edges: [ + { + node: { + _id: '7', + name: 'Advertisement7', + startDate: '2022-01-01', + endDate: '2023-01-01', + mediaUrl: 'http://example1.com', + }, + cursor: '5rdiyruyu3hkjkjiwfhwaify', + }, + { + node: { + _id: '8', + name: 'Advertisement8', + startDate: '2024-02-01', + endDate: '2025-02-01', + mediaUrl: 'http://example2.com', + }, + cursor: '5rdiyrhgkjkjjyg3iwfhwaify', + }, + ], + pageInfo: { + startCursor: '5rdiyruyu3hkjkjiwfhwaify', + endCursor: '5rdiyrhgkjkjjyg3iwfhwaify', + hasNextPage: false, + hasPreviousPage: true, + }, + totalCount: 8, + }, + }, + ], + }, + }, + }, + { + request: { + query: ORGANIZATION_ADVERTISEMENT_LIST, + variables: { + id: '1', + first: 6, + after: 'cursor2', + }, + }, + result: { + data: { + organizations: [ + { + _id: '1', + advertisements: { + edges: [ + { + node: { + _id: '7', + name: 'Advertisement7', + startDate: '2022-01-01', + endDate: '2023-01-01', + mediaUrl: 'http://example1.com', + }, + cursor: '5rdiyruyu3hkjkjiwfhwaify', + }, + { + node: { + _id: '8', + name: 'Advertisement8', + startDate: '2024-02-01', + endDate: '2025-02-01', + mediaUrl: 'http://example2.com', + }, + cursor: '5rdiyrhgkjkjjyg3iwfhwaify', + }, + ], + pageInfo: { + startCursor: '5rdiyruyu3hkjkjiwfhwaify', + endCursor: '5rdiyrhgkjkjjyg3iwfhwaify', + hasNextPage: false, + hasPreviousPage: true, + }, + totalCount: 8, + }, + }, + ], + }, + }, + }, + ]; + + render( + + + + + + + + + + + , + ); + let moreiconbtn = await screen.findAllByTestId('moreiconbtn'); + console.log('before scroll', moreiconbtn); + fireEvent.scroll(window, { target: { scrollY: 500 } }); + moreiconbtn = await screen.findAllByTestId('moreiconbtn'); + console.log('after scroll', moreiconbtn); + }); +}); diff --git a/src/components/Advertisements/Advertisements.tsx b/src/components/Advertisements/Advertisements.tsx new file mode 100644 index 0000000000..0b880700d9 --- /dev/null +++ b/src/components/Advertisements/Advertisements.tsx @@ -0,0 +1,243 @@ +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 { 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'; + +export default function advertisements(): JSX.Element { + const { orgId: currentOrgId } = useParams(); + const { t } = useTranslation('translation', { keyPrefix: 'advertisement' }); + const { t: tCommon } = useTranslation('common'); + document.title = t('title'); + const [after, setAfter] = useState(null); + + type Ad = { + _id: string; + name: string; + type: 'BANNER' | 'MENU' | 'POPUP'; + mediaUrl: string; + endDate: string; // Assuming it's a string in the format 'yyyy-MM-dd' + startDate: string; // Assuming it's a string in the format 'yyyy-MM-dd' + }; + + const { + data: orgAdvertisementListData, + refetch, + }: { + data?: { + organizations: InterfaceQueryOrganizationAdvertisementListItem[]; + }; + refetch: () => void; + } = useQuery(ORGANIZATION_ADVERTISEMENT_LIST, { + variables: { + id: currentOrgId, + after: after, + first: 6, + }, + }); + const [advertisements, setAdvertisements] = useState( + orgAdvertisementListData?.organizations[0].advertisements?.edges.map( + (edge: { node: Ad }) => edge.node, + ) || [], + ); + + useEffect(() => { + if (orgAdvertisementListData && orgAdvertisementListData.organizations) { + const ads: Ad[] = + orgAdvertisementListData.organizations[0].advertisements?.edges.map( + (edge) => edge.node, + ); + after + ? setAdvertisements([...advertisements, ...ads]) + : setAdvertisements(ads); + } + }, [orgAdvertisementListData, after]); + + async function loadMoreAdvertisements(): Promise { + await refetch(); + + if (orgAdvertisementListData && orgAdvertisementListData.organizations) { + setAfter( + orgAdvertisementListData?.organizations[0]?.advertisements.pageInfo + .endCursor, + ); + } + } + + return ( + <> + + +
+ + + + + {[...Array(6)].map((_, index) => ( +
+
+
+
+
+
+
+
+
+
+
+ ))} + + } + hasMore={ + orgAdvertisementListData?.organizations[0].advertisements + .pageInfo.hasNextPage ?? false + } + className={styles.listBox} + data-testid="organizations-list" + endMessage={ + advertisements.filter( + (ad: Ad) => new Date(ad.endDate) > new Date(), + ).length !== 0 && ( +
+
{tCommon('endOfResults')}
+
+ ) + } + > + {advertisements.filter( + (ad: Ad) => new Date(ad.endDate) > new Date(), + ).length === 0 ? ( +

{t('pMessage')}

+ ) : ( + advertisements + .filter((ad: Ad) => new Date(ad.endDate) > new Date()) + .map( + ( + ad: { + _id: string; + name: string | undefined; + type: string | undefined; + mediaUrl: string; + endDate: string; + startDate: string; + }, + i: React.Key | null | undefined, + ): JSX.Element => ( + + ), + ) + )} + + + + + {[...Array(6)].map((_, index) => ( +
+
+
+
+
+
+
+
+
+
+
+ ))} + + } + hasMore={ + orgAdvertisementListData?.organizations[0].advertisements + .pageInfo.hasNextPage ?? false + } + className={styles.listBox} + data-testid="organizations-list" + endMessage={ + advertisements.filter( + (ad: Ad) => new Date(ad.endDate) < new Date(), + ).length !== 0 && ( +
+
{tCommon('endOfResults')}
+
+ ) + } + > + {advertisements.filter( + (ad: Ad) => new Date(ad.endDate) < new Date(), + ).length === 0 ? ( +

{t('pMessage')}

+ ) : ( + advertisements + .filter((ad: Ad) => new Date(ad.endDate) < new Date()) + .map( + ( + ad: { + _id: string; + name: string | undefined; + type: string | undefined; + mediaUrl: string; + endDate: string; + startDate: string; + }, + i: React.Key | null | undefined, + ): JSX.Element => ( + + ), + ) + )} + + + +
+ + + + ); +} + +advertisements.defaultProps = {}; + +advertisements.propTypes = {}; diff --git a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.module.css b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.module.css new file mode 100644 index 0000000000..879d96a0a0 --- /dev/null +++ b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.module.css @@ -0,0 +1,75 @@ +.entrytoggle { + margin: 24px 24px 0 auto; + width: fit-content; +} + +.entryaction { + display: flex !important; +} + +.entryaction i { + margin-right: 8px; + margin-top: 4px; +} + +.entryaction .spinner-grow { + height: 1rem; + width: 1rem; + margin-right: 8px; +} + +.admedia { + object-fit: cover; + height: 20rem; +} + +.buttons { + display: flex; + justify-content: flex-end; +} + +.dropdownButton { + background-color: transparent; + color: #000; + border: none; + cursor: pointer; + display: flex; + width: 100%; + justify-content: flex-end; + padding: 8px 10px; +} + +.dropdownContainer { + position: relative; + display: inline-block; +} + +.dropdownmenu { + display: none; + position: absolute; + z-index: 1; + background-color: white; + width: 120px; + box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2); + padding: 5px 0; + margin: 0; + list-style-type: none; + right: 0; + top: 100%; +} + +.dropdownmenu li { + cursor: pointer; + padding: 8px 16px; + text-decoration: none; + display: block; + color: #333; +} + +.dropdownmenu li:hover { + background-color: #f1f1f1; +} + +.dropdownContainer:hover .dropdownmenu { + display: block; +} diff --git a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.test.tsx b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.test.tsx new file mode 100644 index 0000000000..0850d1f89f --- /dev/null +++ b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.test.tsx @@ -0,0 +1,580 @@ +import React from 'react'; +import { render, fireEvent, waitFor, screen } from '@testing-library/react'; +import { + ApolloClient, + ApolloProvider, + InMemoryCache, + ApolloLink, + HttpLink, +} from '@apollo/client'; +import type { NormalizedCacheObject } from '@apollo/client'; +import { BrowserRouter } from 'react-router-dom'; +import AdvertisementEntry from './AdvertisementEntry'; +import AdvertisementRegister from '../AdvertisementRegister/AdvertisementRegister'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import { BACKEND_URL } from 'Constant/constant'; +import i18nForTest from 'utils/i18nForTest'; +import { I18nextProvider } from 'react-i18next'; +import dayjs from 'dayjs'; +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'; + +const { getItem } = useLocalStorage(); + +const httpLink = new HttpLink({ + uri: BACKEND_URL, + headers: { + authorization: 'Bearer ' + getItem('token') || '', + }, +}); + +const translations = JSON.parse( + JSON.stringify( + i18nForTest.getDataByLanguage('en')?.translation?.advertisement ?? null, + ), +); + +const client: ApolloClient = new ApolloClient({ + cache: new InMemoryCache(), + link: ApolloLink.from([httpLink]), +}); + +const mockUseMutation = jest.fn(); +jest.mock('@apollo/client', () => { + const originalModule = jest.requireActual('@apollo/client'); + return { + ...originalModule, + useMutation: () => mockUseMutation(), + }; +}); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: '1' }), +})); + +describe('Testing Advertisement Entry Component', () => { + test('Testing rendering and deleting of advertisement', async () => { + const deleteAdByIdMock = jest.fn(); + mockUseMutation.mockReturnValue([deleteAdByIdMock]); + const { getByTestId, getAllByText } = render( + + + + + + + + + , + ); + + //Testing rendering + expect(getByTestId('AdEntry')).toBeInTheDocument(); + expect(getAllByText('POPUP')[0]).toBeInTheDocument(); + expect(getAllByText('Advert1')[0]).toBeInTheDocument(); + expect(screen.getByTestId('media')).toBeInTheDocument(); + + //Testing successful deletion + fireEvent.click(getByTestId('moreiconbtn')); + fireEvent.click(getByTestId('deletebtn')); + + await waitFor(() => { + expect(screen.getByTestId('delete_title')).toBeInTheDocument(); + expect(screen.getByTestId('delete_body')).toBeInTheDocument(); + }); + + fireEvent.click(getByTestId('delete_yes')); + + await waitFor(() => { + expect(deleteAdByIdMock).toHaveBeenCalledWith({ + variables: { + id: '1', + }, + }); + const deletedMessage = screen.queryByText('Advertisement Deleted'); + expect(deletedMessage).toBeNull(); + }); + + //Testing unsuccessful deletion + deleteAdByIdMock.mockRejectedValueOnce(new Error('Deletion Failed')); + + fireEvent.click(getByTestId('moreiconbtn')); + + fireEvent.click(getByTestId('delete_yes')); + + await waitFor(() => { + expect(deleteAdByIdMock).toHaveBeenCalledWith({ + variables: { + id: '1', + }, + }); + const deletionFailedText = screen.queryByText((content, element) => { + return ( + element?.textContent === 'Deletion Failed' && + element.tagName.toLowerCase() === 'div' + ); + }); + expect(deletionFailedText).toBeNull(); + }); + }); + + it('should open and close the dropdown when options button is clicked', () => { + const { getByTestId, queryByText, getAllByText } = render( + + + + + + + + + , + ); + + // Test initial rendering + expect(getByTestId('AdEntry')).toBeInTheDocument(); + expect(getAllByText('POPUP')[0]).toBeInTheDocument(); + expect(getAllByText('Advert1')[0]).toBeInTheDocument(); + + // Test dropdown functionality + const optionsButton = getByTestId('moreiconbtn'); + + // Initially, the dropdown should not be visible + expect(queryByText('Edit')).toBeNull(); + + // Click to open the dropdown + fireEvent.click(optionsButton); + + // After clicking the button, the dropdown should be visible + expect(queryByText('Edit')).toBeInTheDocument(); + + // Click again to close the dropdown + fireEvent.click(optionsButton); + + // After the second click, the dropdown should be hidden again + expect(queryByText('Edit')).toBeNull(); + }); + + test('Updates the advertisement and shows success toast on successful update', async () => { + const updateAdByIdMock = jest.fn().mockResolvedValue({ + data: { + updateAdvertisement: { + advertisement: { + _id: '1', + name: 'Updated Advertisement', + mediaUrl: '', + startDate: dayjs(new Date()).add(1, 'day').format('YYYY-MM-DD'), + endDate: dayjs(new Date()).add(2, 'days').format('YYYY-MM-DD'), + type: 'BANNER', + }, + }, + }, + }); + + mockUseMutation.mockReturnValue([updateAdByIdMock]); + + render( + + + + + + + + + , + ); + + const optionsButton = screen.getByTestId('moreiconbtn'); + fireEvent.click(optionsButton); + fireEvent.click(screen.getByTestId('editBtn')); + + fireEvent.change(screen.getByLabelText('Enter name of Advertisement'), { + target: { value: 'Updated Advertisement' }, + }); + + expect(screen.getByLabelText('Enter name of Advertisement')).toHaveValue( + 'Updated Advertisement', + ); + + fireEvent.change(screen.getByLabelText(translations.Rtype), { + target: { value: 'BANNER' }, + }); + expect(screen.getByLabelText(translations.Rtype)).toHaveValue('BANNER'); + + fireEvent.change(screen.getByLabelText(translations.RstartDate), { + target: { value: dayjs().add(1, 'day').format('YYYY-MM-DD') }, + }); + + fireEvent.change(screen.getByLabelText(translations.RendDate), { + target: { value: dayjs().add(2, 'days').format('YYYY-MM-DD') }, + }); + + fireEvent.click(screen.getByTestId('addonupdate')); + + expect(updateAdByIdMock).toHaveBeenCalledWith({ + variables: { + id: '1', + name: 'Updated Advertisement', + type: 'BANNER', + startDate: dayjs().add(1, 'day').format('YYYY-MM-DD'), + endDate: dayjs().add(2, 'days').format('YYYY-MM-DD'), + }, + }); + }); + + test('Simulating if the mutation doesnt have data variable while updating', async () => { + const updateAdByIdMock = jest.fn().mockResolvedValue({ + updateAdvertisement: { + _id: '1', + name: 'Updated Advertisement', + type: 'BANNER', + }, + }); + + mockUseMutation.mockReturnValue([updateAdByIdMock]); + + render( + + + + + + + + + , + ); + + const optionsButton = screen.getByTestId('moreiconbtn'); + fireEvent.click(optionsButton); + fireEvent.click(screen.getByTestId('editBtn')); + + fireEvent.change(screen.getByLabelText('Enter name of Advertisement'), { + target: { value: 'Updated Advertisement' }, + }); + + expect(screen.getByLabelText('Enter name of Advertisement')).toHaveValue( + 'Updated Advertisement', + ); + + fireEvent.change(screen.getByLabelText(translations.Rtype), { + target: { value: 'BANNER' }, + }); + expect(screen.getByLabelText(translations.Rtype)).toHaveValue('BANNER'); + + fireEvent.click(screen.getByTestId('addonupdate')); + + expect(updateAdByIdMock).toHaveBeenCalledWith({ + variables: { + id: '1', + name: 'Updated Advertisement', + type: 'BANNER', + }, + }); + }); + + 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', + }, + }); + const createAdByIdMock = jest.fn().mockResolvedValue({ + data1: { + createAdvertisement: { + _id: '1', + }, + }, + }); + + mockUseMutation.mockReturnValue([createAdByIdMock]); + + render( + + + + + { + + } + + + + , + ); + + fireEvent.click(screen.getByTestId('createAdvertisement')); + + fireEvent.change(screen.getByLabelText('Enter name of Advertisement'), { + target: { value: 'Updated Advertisement' }, + }); + + expect(screen.getByLabelText('Enter name of Advertisement')).toHaveValue( + 'Updated Advertisement', + ); + + fireEvent.change(screen.getByLabelText(translations.Rtype), { + target: { value: 'BANNER' }, + }); + expect(screen.getByLabelText(translations.Rtype)).toHaveValue('BANNER'); + + fireEvent.change(screen.getByLabelText(translations.RstartDate), { + target: { value: '2023-01-01' }, + }); + expect(screen.getByLabelText(translations.RstartDate)).toHaveValue( + '2023-01-01', + ); + + fireEvent.change(screen.getByLabelText(translations.RendDate), { + target: { value: '2023-02-01' }, + }); + expect(screen.getByLabelText(translations.RendDate)).toHaveValue( + '2023-02-01', + ); + + fireEvent.click(screen.getByTestId('addonregister')); + + expect(createAdByIdMock).toHaveBeenCalledWith({ + variables: { + organizationId: '1', + name: 'Updated Advertisement', + file: '', + type: 'BANNER', + startDate: dayjs(new Date('2023-01-01')).format('YYYY-MM-DD'), + endDate: dayjs(new Date('2023-02-01')).format('YYYY-MM-DD'), + }, + }); + }); + test('delet advertisement', async () => { + const deleteAdByIdMock = jest.fn(); + const mocks = [ + { + request: { + query: ORGANIZATION_ADVERTISEMENT_LIST, + variables: { + id: '1', + first: 2, + after: null, + last: null, + before: null, + }, + }, + result: { + data: { + organizations: [ + { + _id: '1', + advertisements: { + edges: [ + { + node: { + _id: '1', + name: 'Advertisement1', + startDate: '2022-01-01', + endDate: '2023-01-01', + mediaUrl: 'http://example1.com', + }, + cursor: 'cursor1', + }, + { + node: { + _id: '2', + name: 'Advertisement2', + startDate: '2024-02-01', + endDate: '2025-02-01', + mediaUrl: 'http://example2.com', + }, + cursor: 'cursor2', + }, + { + node: { + _id: '3', + name: 'Advertisement1', + startDate: '2022-01-01', + endDate: '2023-01-01', + mediaUrl: 'http://example1.com', + }, + cursor: 'cursor3', + }, + { + node: { + _id: '4', + name: 'Advertisement2', + startDate: '2024-02-01', + endDate: '2025-02-01', + mediaUrl: 'http://example2.com', + }, + cursor: 'cursor4', + }, + { + node: { + _id: '5', + name: 'Advertisement1', + startDate: '2022-01-01', + endDate: '2023-01-01', + mediaUrl: 'http://example1.com', + }, + cursor: 'cursor5', + }, + { + node: { + _id: '6', + name: 'Advertisement2', + startDate: '2024-02-01', + endDate: '2025-02-01', + mediaUrl: 'http://example2.com', + }, + cursor: 'cursor6', + }, + ], + pageInfo: { + startCursor: 'cursor1', + endCursor: 'cursor6', + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 8, + }, + }, + ], + }, + }, + }, + { + request: { + query: DELETE_ADVERTISEMENT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + advertisements: { + _id: null, + }, + }, + }, + }, + ]; + mockUseMutation.mockReturnValue([deleteAdByIdMock]); + const { getByTestId, getAllByText } = render( + + + + + + + + + + + , + ); + + //Testing rendering + expect(getByTestId('AdEntry')).toBeInTheDocument(); + expect(getAllByText('POPUP')[0]).toBeInTheDocument(); + expect(getAllByText('Advert1')[0]).toBeInTheDocument(); + expect(screen.getByTestId('media')).toBeInTheDocument(); + + //Testing successful deletion + fireEvent.click(getByTestId('moreiconbtn')); + fireEvent.click(getByTestId('deletebtn')); + + await waitFor(() => { + expect(screen.getByTestId('delete_title')).toBeInTheDocument(); + expect(screen.getByTestId('delete_body')).toBeInTheDocument(); + }); + + fireEvent.click(getByTestId('delete_yes')); + + await waitFor(() => { + expect(deleteAdByIdMock).toHaveBeenCalledWith({ + variables: { + id: '1', + }, + }); + const deletedMessage = screen.queryByText('Advertisement Deleted'); + expect(deletedMessage).toBeNull(); + }); + + //Testing unsuccessful deletion + deleteAdByIdMock.mockRejectedValueOnce(new Error('Deletion Failed')); + + fireEvent.click(getByTestId('moreiconbtn')); + + fireEvent.click(getByTestId('delete_yes')); + + await waitFor(() => { + expect(deleteAdByIdMock).toHaveBeenCalledWith({ + variables: { + id: '1', + }, + }); + const deletionFailedText = screen.queryByText((content, element) => { + return ( + element?.textContent === 'Deletion Failed' && + element.tagName.toLowerCase() === 'div' + ); + }); + expect(deletionFailedText).toBeNull(); + }); + }); +}); diff --git a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.tsx b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.tsx new file mode 100644 index 0000000000..afb66e7ff4 --- /dev/null +++ b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.tsx @@ -0,0 +1,203 @@ +import React, { useState } from 'react'; +import PropTypes from 'prop-types'; +import styles from './AdvertisementEntry.module.css'; +import { Button, Card, Col, Row, Spinner, Modal } from 'react-bootstrap'; +import { DELETE_ADVERTISEMENT_BY_ID } from 'GraphQl/Mutations/mutations'; +import { useMutation } from '@apollo/client'; +import { useTranslation } from 'react-i18next'; +import { ORGANIZATION_ADVERTISEMENT_LIST } from 'GraphQl/Queries/Queries'; +import AdvertisementRegister from '../AdvertisementRegister/AdvertisementRegister'; +import MoreVertIcon from '@mui/icons-material/MoreVert'; +import { toast } from 'react-toastify'; + +interface InterfaceAddOnEntryProps { + id: string; + name: string; + mediaUrl: string; + type: string; + organizationId: string; + startDate: Date; + endDate: Date; + setAfter: React.Dispatch>; +} +function advertisementEntry({ + id, + name, + type, + mediaUrl, + endDate, + organizationId, + startDate, + setAfter, +}: InterfaceAddOnEntryProps): JSX.Element { + const { t } = useTranslation('translation', { keyPrefix: 'advertisement' }); + const { t: tCommon } = useTranslation('common'); + const [buttonLoading, setButtonLoading] = useState(false); + const [dropdown, setDropdown] = useState(false); + const [showDeleteModal, setShowDeleteModal] = useState(false); + + const [deleteAdById] = useMutation(DELETE_ADVERTISEMENT_BY_ID, { + refetchQueries: [ + { + query: ORGANIZATION_ADVERTISEMENT_LIST, + variables: { first: 6, after: null, id: organizationId }, + }, + ], + }); + + const toggleShowDeleteModal = (): void => setShowDeleteModal((prev) => !prev); + const onDelete = async (): Promise => { + setButtonLoading(true); + try { + await deleteAdById({ + variables: { + id: id.toString(), + }, + }); + toast.success(t('advertisementDeleted')); + setButtonLoading(false); + setAfter(null); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + } + setButtonLoading(false); + } + }; + const handleOptionsClick = (): void => { + setDropdown(!dropdown); + }; + return ( + <> + + {Array.from({ length: 1 }).map((_, idx) => ( + + +
+ + {dropdown && ( +
    +
  • + +
  • +
  • + {tCommon('delete')} +
  • +
+ )} +
+ {mediaUrl?.includes('videos') ? ( + + ) : ( + + )} + + {name} + + Ends on {endDate?.toDateString()} + + + {type} + +
+ +
+ + +
+ {t('deleteAdvertisement')} +
+ +
+ + {t('deleteAdvertisementMsg')} + + + + + +
+
+
+ + ))} +
+
+ + ); +} + +advertisementEntry.propTypes = { + name: PropTypes.string, + type: PropTypes.string, + organizationId: PropTypes.string, + mediaUrl: PropTypes.string, + endDate: PropTypes.instanceOf(Date), + startDate: PropTypes.instanceOf(Date), +}; + +advertisementEntry.defaultProps = { + name: '', + type: '', + organizationId: '', + mediaUrl: '', + endDate: new Date(), + startDate: new Date(), +}; +export default advertisementEntry; diff --git a/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.module.css b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.module.css new file mode 100644 index 0000000000..75b90fd1d7 --- /dev/null +++ b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.module.css @@ -0,0 +1,55 @@ +.modalbtn { + display: flex !important; + margin-left: auto; + align-items: center; +} + +.modalbtn i, +.button i { + margin-right: 8px; +} + +.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; +} + +.closeButton { + 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; +} + +.button { + min-width: 102px; +} + +.editHeader { + background-color: #31bb6b; + color: white; +} + +.link_check { + display: flex; + justify-content: center; + align-items: flex-start; +} diff --git a/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.test.tsx b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.test.tsx new file mode 100644 index 0000000000..c3aa536d1f --- /dev/null +++ b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.test.tsx @@ -0,0 +1,566 @@ +import React from 'react'; +import { render, fireEvent, waitFor, screen } from '@testing-library/react'; + +import { + ApolloClient, + ApolloProvider, + InMemoryCache, + ApolloLink, + HttpLink, +} from '@apollo/client'; + +import type { NormalizedCacheObject } from '@apollo/client'; +import { BrowserRouter } from 'react-router-dom'; +import AdvertisementRegister from './AdvertisementRegister'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import { BACKEND_URL } from 'Constant/constant'; +// import i18nForTest from 'utils/i18nForTest'; +import { I18nextProvider } from 'react-i18next'; +import { MockedProvider } from '@apollo/client/testing'; +import i18n from 'utils/i18nForTest'; +import { toast } from 'react-toastify'; +import { ADD_ADVERTISEMENT_MUTATION } from 'GraphQl/Mutations/mutations'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import userEvent from '@testing-library/user-event'; +import useLocalStorage from 'utils/useLocalstorage'; +import { ORGANIZATION_ADVERTISEMENT_LIST } from 'GraphQl/Queries/Queries'; + +const { getItem } = useLocalStorage(); + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }, +})); + +const MOCKS = [ + { + request: { + query: ADD_ADVERTISEMENT_MUTATION, + variables: { + organizationId: '1', + name: 'Ad1', + type: 'BANNER', + startDate: '2023-01-01', + endDate: '2023-02-01', + file: 'data:image/png;base64,bWVkaWEgY29udGVudA==', + }, + }, + result: { + data: { + createAdvertisement: { + _id: '1', + advertisement: null, + __typename: 'Advertisement', + }, + }, + }, + }, + { + request: { + query: ORGANIZATION_ADVERTISEMENT_LIST, + variables: { + id: '1', + first: 6, + after: null, + }, + }, + result: { + data: { + organizations: [ + { + _id: '1', + advertisements: { + edges: [ + { + node: { + _id: '1', + name: 'Advertisement1', + startDate: '2022-01-01', + endDate: '2023-01-01', + mediaUrl: 'http://example1.com', + }, + cursor: '5rdiyr3iwfhwaify', + }, + { + node: { + _id: '2', + name: 'Advertisement2', + startDate: '2024-02-01', + endDate: '2025-02-01', + mediaUrl: 'http://example2.com', + }, + cursor: '5rdiyr3iwfhwaify', + }, + ], + pageInfo: { + startCursor: 'erdftgyhujkerty', + endCursor: 'edrftgyhujikl', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 2, + }, + }, + ], + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); + +const httpLink = new HttpLink({ + uri: BACKEND_URL, + headers: { + authorization: 'Bearer ' + getItem('token') || '', + }, +}); + +const client: ApolloClient = new ApolloClient({ + cache: new InMemoryCache(), + link: ApolloLink.from([httpLink]), +}); + +const translations = { + ...JSON.parse( + JSON.stringify( + i18n.getDataByLanguage('en')?.translation.advertisement ?? {}, + ), + ), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), +}; + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: '1' }), +})); +describe('Testing Advertisement Register Component', () => { + test('AdvertismentRegister component loads correctly in register mode', async () => { + const { getByText } = render( + + + + + + + + + , + ); + await waitFor(() => { + expect(getByText(translations.createAdvertisement)).toBeInTheDocument(); + }); + }); + + test('create advertisement', async () => { + const setTimeoutSpy = jest.spyOn(global, 'setTimeout'); + const { getByText, queryByText, getByLabelText } = render( + + + + + + + + + , + ); + + expect(getByText(translations.createAdvertisement)).toBeInTheDocument(); + + fireEvent.click(getByText(translations.createAdvertisement)); + expect(queryByText(translations.addNew)).toBeInTheDocument(); + + fireEvent.change(getByLabelText(translations.Rname), { + target: { value: 'Ad1' }, + }); + expect(getByLabelText(translations.Rname)).toHaveValue('Ad1'); + + const mediaFile = new File(['media content'], 'test.png', { + type: 'image/png', + }); + + const mediaInput = getByLabelText(translations.Rmedia); + fireEvent.change(mediaInput, { + target: { + files: [mediaFile], + }, + }); + + const mediaPreview = await screen.findByTestId('mediaPreview'); + expect(mediaPreview).toBeInTheDocument(); + + fireEvent.change(getByLabelText(translations.Rtype), { + target: { value: 'BANNER' }, + }); + expect(getByLabelText(translations.Rtype)).toHaveValue('BANNER'); + + fireEvent.change(getByLabelText(translations.RstartDate), { + target: { value: '2023-01-01' }, + }); + expect(getByLabelText(translations.RstartDate)).toHaveValue('2023-01-01'); + + fireEvent.change(getByLabelText(translations.RendDate), { + target: { value: '2023-02-01' }, + }); + expect(getByLabelText(translations.RendDate)).toHaveValue('2023-02-01'); + + await waitFor(() => { + fireEvent.click(getByText(translations.register)); + }); + expect(toast.success).toBeCalledWith('Advertisement created successfully.'); + expect(setTimeoutSpy).toHaveBeenCalled(); + }); + + test('update advertisement', async () => { + const setTimeoutSpy = jest.spyOn(global, 'setTimeout'); + const { getByText, getByLabelText } = render( + + + + + + + + + , + ); + + fireEvent.click(getByText(translations.edit)); + + fireEvent.change(getByLabelText(translations.Rname), { + target: { value: 'Ad1' }, + }); + expect(getByLabelText(translations.Rname)).toHaveValue('Ad1'); + + const mediaFile = new File(['media content'], 'test.png', { + type: 'image/png', + }); + + const mediaInput = getByLabelText(translations.Rmedia); + fireEvent.change(mediaInput, { + target: { + files: [mediaFile], + }, + }); + + const mediaPreview = await screen.findByTestId('mediaPreview'); + expect(mediaPreview).toBeInTheDocument(); + + fireEvent.change(getByLabelText(translations.Rtype), { + target: { value: 'BANNER' }, + }); + expect(getByLabelText(translations.Rtype)).toHaveValue('BANNER'); + + fireEvent.change(getByLabelText(translations.RstartDate), { + target: { value: '2023-01-01' }, + }); + expect(getByLabelText(translations.RstartDate)).toHaveValue('2023-01-01'); + + fireEvent.change(getByLabelText(translations.RendDate), { + target: { value: '2023-02-01' }, + }); + expect(getByLabelText(translations.RendDate)).toHaveValue('2023-02-01'); + + await waitFor(() => { + fireEvent.click(getByText(translations.saveChanges)); + }); + expect(toast.success).toBeCalledWith('Advertisement created successfully.'); + expect(setTimeoutSpy).toHaveBeenCalled(); + }); + + test('Logs error to the console and shows error toast when advertisement creation fails', async () => { + const setTimeoutSpy = jest.spyOn(global, 'setTimeout'); + const { getByText, queryByText } = render( + + + + + + + + + , + ); + + expect(getByText(translations.createAdvertisement)).toBeInTheDocument(); + + fireEvent.click(getByText(translations.createAdvertisement)); + expect(queryByText(translations.addNew)).toBeInTheDocument(); + + await waitFor(() => { + fireEvent.click(getByText(translations.register)); + }); + expect(toast.error).toBeCalledWith( + `An error occurred. Couldn't create advertisement`, + ); + expect(setTimeoutSpy).toHaveBeenCalled(); + }); + + test('Throws error when the end date is less than the start date', async () => { + const setTimeoutSpy = jest.spyOn(global, 'setTimeout'); + const { getByText, queryByText, getByLabelText } = render( + + + + + + + + + , + ); + + expect(getByText(translations.createAdvertisement)).toBeInTheDocument(); + + fireEvent.click(getByText(translations.createAdvertisement)); + expect(queryByText(translations.addNew)).toBeInTheDocument(); + + fireEvent.change(getByLabelText(translations.Rname), { + target: { value: 'Ad1' }, + }); + expect(getByLabelText(translations.Rname)).toHaveValue('Ad1'); + + const mediaFile = new File(['media content'], 'test.png', { + type: 'image/png', + }); + + const mediaInput = getByLabelText(translations.Rmedia); + fireEvent.change(mediaInput, { + target: { + files: [mediaFile], + }, + }); + + const mediaPreview = await screen.findByTestId('mediaPreview'); + expect(mediaPreview).toBeInTheDocument(); + + fireEvent.change(getByLabelText(translations.Rtype), { + target: { value: 'BANNER' }, + }); + expect(getByLabelText(translations.Rtype)).toHaveValue('BANNER'); + + fireEvent.change(getByLabelText(translations.RstartDate), { + target: { value: '2023-01-01' }, + }); + expect(getByLabelText(translations.RstartDate)).toHaveValue('2023-01-01'); + + fireEvent.change(getByLabelText(translations.RendDate), { + target: { value: '2022-02-01' }, + }); + expect(getByLabelText(translations.RendDate)).toHaveValue('2022-02-01'); + + await waitFor(() => { + fireEvent.click(getByText(translations.register)); + }); + expect(toast.error).toBeCalledWith( + 'End Date should be greater than or equal to Start Date', + ); + expect(setTimeoutSpy).toHaveBeenCalled(); + }); + + test('AdvertismentRegister component loads correctly in edit mode', async () => { + render( + + + + + + + + + , + ); + await waitFor(() => { + expect(screen.getByTestId('editBtn')).toBeInTheDocument(); + }); + }); + + test('Opens and closes modals on button click', async () => { + const { getByText, queryByText } = render( + + + + + + + + + , + ); + fireEvent.click(getByText(translations.createAdvertisement)); + await waitFor(() => { + expect(queryByText(translations.addNew)).toBeInTheDocument(); + }); + fireEvent.click(getByText(translations.close)); + await waitFor(() => { + expect(queryByText(translations.close)).not.toBeInTheDocument(); + }); + }); + + test('Throws error when the end date is less than the start date while editing the advertisement', async () => { + const { getByText, getByLabelText, queryByText } = render( + + + + + { + + } + + + + , + ); + + fireEvent.click(getByText(translations.edit)); + expect(queryByText(translations.editAdvertisement)).toBeInTheDocument(); + fireEvent.change(getByLabelText(translations.Rname), { + target: { value: 'Test Advertisement' }, + }); + expect(getByLabelText(translations.Rname)).toHaveValue( + 'Test Advertisement', + ); + + const mediaFile = new File(['video content'], 'test.mp4', { + type: 'video/mp4', + }); + const mediaInput = screen.getByTestId('advertisementMedia'); + userEvent.upload(mediaInput, mediaFile); + + const mediaPreview = await screen.findByTestId('mediaPreview'); + expect(mediaPreview).toBeInTheDocument(); + + fireEvent.change(getByLabelText(translations.Rtype), { + target: { value: 'BANNER' }, + }); + expect(getByLabelText(translations.Rtype)).toHaveValue('BANNER'); + + fireEvent.change(getByLabelText(translations.RstartDate), { + target: { value: '2023-02-02' }, + }); + expect(getByLabelText(translations.RstartDate)).toHaveValue('2023-02-02'); + + fireEvent.change(getByLabelText(translations.RendDate), { + target: { value: '2023-01-01' }, + }); + expect(getByLabelText(translations.RendDate)).toHaveValue('2023-01-01'); + + fireEvent.click(getByText(translations.saveChanges)); + await waitFor(() => { + expect(toast.error).toBeCalledWith( + 'End Date should be greater than or equal to Start Date', + ); + }); + }); + + test('Media preview renders correctly', async () => { + render( + + + + + + + + + , + ); + + fireEvent.click(screen.getByText(translations.createAdvertisement)); + await screen.findByText(translations.addNew); + + const mediaFile = new File(['video content'], 'test.mp4', { + type: 'video/mp4', + }); + const mediaInput = screen.getByTestId('advertisementMedia'); + userEvent.upload(mediaInput, mediaFile); + + const mediaPreview = await screen.findByTestId('mediaPreview'); + expect(mediaPreview).toBeInTheDocument(); + + const closeButton = await screen.findByTestId('closePreview'); + fireEvent.click(closeButton); + expect(mediaPreview).not.toBeInTheDocument(); + }); +}); diff --git a/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.tsx b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.tsx new file mode 100644 index 0000000000..ee812f2b00 --- /dev/null +++ b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.tsx @@ -0,0 +1,421 @@ +import React, { useState, useEffect } from 'react'; +import PropTypes from 'prop-types'; +import styles from './AdvertisementRegister.module.css'; +import { Button, Form, Modal } from 'react-bootstrap'; +import { + ADD_ADVERTISEMENT_MUTATION, + UPDATE_ADVERTISEMENT_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import { useMutation } from '@apollo/client'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; +import dayjs from 'dayjs'; +import convertToBase64 from 'utils/convertToBase64'; +import { ORGANIZATION_ADVERTISEMENT_LIST } from 'GraphQl/Queries/Queries'; +import { useParams } from 'react-router-dom'; +interface InterfaceAddOnRegisterProps { + id?: string; // organizationId + createdBy?: string; // User + formStatus?: string; + idEdit?: string; + nameEdit?: string; + typeEdit?: string; + orgIdEdit?: string; + advertisementMediaEdit?: string; + endDateEdit?: Date; + startDateEdit?: Date; + setAfter: React.Dispatch>; +} +interface InterfaceFormStateTypes { + name: string; + advertisementMedia: string; + type: string; + startDate: Date; + endDate: Date; + organizationId: string | undefined; +} + +function advertisementRegister({ + formStatus, + idEdit, + nameEdit, + typeEdit, + advertisementMediaEdit, + endDateEdit, + startDateEdit, + setAfter, +}: InterfaceAddOnRegisterProps): JSX.Element { + const { t } = useTranslation('translation', { keyPrefix: 'advertisement' }); + const { t: tCommon } = useTranslation('common'); + const { t: tErrors } = useTranslation('errors'); + + const { orgId: currentOrg } = useParams(); + + const [show, setShow] = useState(false); + const handleClose = (): void => setShow(false); + const handleShow = (): void => setShow(true); + const [create] = useMutation(ADD_ADVERTISEMENT_MUTATION, { + refetchQueries: [ + { + query: ORGANIZATION_ADVERTISEMENT_LIST, + variables: { first: 6, after: null, id: currentOrg }, + }, + ], + }); + const [updateAdvertisement] = useMutation(UPDATE_ADVERTISEMENT_MUTATION, { + refetchQueries: [ + { + query: ORGANIZATION_ADVERTISEMENT_LIST, + variables: { first: 6, after: null, id: currentOrg }, + }, + ], + }); + //getting organizationId from URL + + const [formState, setFormState] = useState({ + name: '', + advertisementMedia: '', + type: 'BANNER', + startDate: new Date(), + endDate: new Date(), + organizationId: currentOrg, + }); + + //if set to edit set the formState by edit variables + useEffect(() => { + if (formStatus === 'edit') { + setFormState((prevState) => ({ + ...prevState, + name: nameEdit || '', + advertisementMedia: advertisementMediaEdit || '', + type: typeEdit || 'BANNER', + startDate: startDateEdit || new Date(), + endDate: endDateEdit || new Date(), + orgId: currentOrg, + })); + } + }, [ + formStatus, + nameEdit, + advertisementMediaEdit, + typeEdit, + startDateEdit, + endDateEdit, + currentOrg, + ]); + + const handleRegister = async (): Promise => { + try { + console.log('At handle register', formState); + if (formState.endDate < formState.startDate) { + toast.error(t('endDateGreaterOrEqual')); + return; + } + const { data } = await create({ + variables: { + organizationId: currentOrg, + name: formState.name as string, + type: formState.type as string, + startDate: dayjs(formState.startDate).format('YYYY-MM-DD'), + endDate: dayjs(formState.endDate).format('YYYY-MM-DD'), + file: formState.advertisementMedia as string, + }, + }); + + if (data) { + toast.success(t('advertisementCreated')); + setFormState({ + name: '', + advertisementMedia: '', + type: 'BANNER', + startDate: new Date(), + endDate: new Date(), + organizationId: currentOrg, + }); + } + setAfter(null); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error( + tErrors('errorOccurredCouldntCreate', { entity: 'advertisement' }), + ); + console.log('error occured', error.message); + } + } + }; + const handleUpdate = async (): Promise => { + try { + const updatedFields: Partial = {}; + + // Only include the fields which are updated + if (formState.name !== nameEdit) { + updatedFields.name = formState.name; + } + if (formState.advertisementMedia !== advertisementMediaEdit) { + updatedFields.advertisementMedia = formState.advertisementMedia; + } + if (formState.type !== typeEdit) { + updatedFields.type = formState.type; + } + if (formState.endDate < formState.startDate) { + toast.error(t('endDateGreaterOrEqual')); + return; + } + const startDateFormattedString = dayjs(formState.startDate).format( + 'YYYY-MM-DD', + ); + const endDateFormattedString = dayjs(formState.endDate).format( + 'YYYY-MM-DD', + ); + + const startDateDate = dayjs( + startDateFormattedString, + 'YYYY-MM-DD', + ).toDate(); + const endDateDate = dayjs(endDateFormattedString, 'YYYY-MM-DD').toDate(); + + if (!dayjs(startDateDate).isSame(startDateEdit, 'day')) { + updatedFields.startDate = startDateDate; + } + if (!dayjs(endDateDate).isSame(endDateEdit, 'day')) { + updatedFields.endDate = endDateDate; + } + + console.log('At handle update', updatedFields); + const { data } = await updateAdvertisement({ + variables: { + id: idEdit, + ...(updatedFields.name && { name: updatedFields.name }), + ...(updatedFields.advertisementMedia && { + file: updatedFields.advertisementMedia, + }), + ...(updatedFields.type && { type: updatedFields.type }), + ...(updatedFields.startDate && { + startDate: startDateFormattedString, + }), + ...(updatedFields.endDate && { endDate: endDateFormattedString }), + }, + }); + + if (data) { + toast.success( + tCommon('updatedSuccessfully', { item: 'Advertisement' }), + ); + handleClose(); + setAfter(null); + } + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + } + } + }; + return ( + //If register show register button else show edit button + <> + {formStatus === 'register' ? ( + + ) : ( +
+ {tCommon('edit')} +
+ )} + + + {formStatus === 'register' ? ( + {t('addNew')} + ) : ( + {t('editAdvertisement')} + )} + + +
+ + {t('Rname')} + { + setFormState({ + ...formState, + name: e.target.value, + }); + }} + /> + + + + {t('Rmedia')} + + , + ): Promise => { + const target = e.target as HTMLInputElement; + const file = target.files && target.files[0]; + if (file) { + const mediaBase64 = await convertToBase64(file); + setFormState({ + ...formState, + advertisementMedia: mediaBase64, + }); + } + }} + /> + {formState.advertisementMedia && ( +
+ {formState.advertisementMedia.includes('video') ? ( + + ) : ( + + )} + +
+ )} +
+ + {t('Rtype')} + { + setFormState({ + ...formState, + type: e.target.value, + }); + }} + > + + + + + + + {t('RstartDate')} + { + setFormState({ + ...formState, + startDate: new Date(e.target.value), + }); + }} + /> + + + + {t('RendDate')} + { + setFormState({ + ...formState, + endDate: new Date(e.target.value), + }); + }} + /> + +
+
+ + + {formStatus === 'register' ? ( + + ) : ( + + )} + +
+ + ); +} + +advertisementRegister.defaultProps = { + name: '', + advertisementMedia: '', + type: 'BANNER', + startDate: new Date(), + endDate: new Date(), + organizationId: '', + formStatus: 'register', +}; + +advertisementRegister.propTypes = { + name: PropTypes.string, + advertisementMedia: PropTypes.string, + type: PropTypes.string, + startDate: PropTypes.instanceOf(Date), + endDate: PropTypes.instanceOf(Date), + organizationId: PropTypes.string, + formStatus: PropTypes.string, +}; + +export default advertisementRegister; diff --git a/src/components/AgendaCategory/AgendaCategoryContainer.module.css b/src/components/AgendaCategory/AgendaCategoryContainer.module.css new file mode 100644 index 0000000000..7ad16b4c7c --- /dev/null +++ b/src/components/AgendaCategory/AgendaCategoryContainer.module.css @@ -0,0 +1,20 @@ +.createModal { + margin-top: 20vh; + margin-left: 13vw; + max-width: 80vw; +} + +.titlemodal { + color: var(--bs-gray-600); + font-weight: 600; + font-size: 20px; + margin-bottom: 20px; + padding-bottom: 5px; + border-bottom: 3px solid var(--bs-primary); + width: 65%; +} + +.agendaCategoryOptionsButton { + width: 24px; + height: 24px; +} diff --git a/src/components/AgendaCategory/AgendaCategoryContainer.test.tsx b/src/components/AgendaCategory/AgendaCategoryContainer.test.tsx new file mode 100644 index 0000000000..5ddab82aec --- /dev/null +++ b/src/components/AgendaCategory/AgendaCategoryContainer.test.tsx @@ -0,0 +1,415 @@ +import React from 'react'; +import { + render, + screen, + waitFor, + act, + waitForElementToBeRemoved, + 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'; +import i18nForTest from 'utils/i18nForTest'; +import { toast } from 'react-toastify'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; + +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; + +import AgendaCategoryContainer from './AgendaCategoryContainer'; +import { props, props2 } from './AgendaCategoryContainerProps'; +import { MOCKS, MOCKS_ERROR_MUTATIONS } from './AgendaCategoryContainerMocks'; + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(MOCKS_ERROR_MUTATIONS, true); + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +async function wait(ms = 100): Promise { + await act(async () => { + return new Promise((resolve) => setTimeout(resolve, ms)); + }); +} + +const translations = JSON.parse( + JSON.stringify( + i18nForTest.getDataByLanguage('en')?.translation.organizationAgendaCategory, + ), +); + +describe('Testing Agenda Category Component', () => { + const formData = { + name: 'AgendaCategory 1 Edited', + description: 'AgendaCategory 1 Description Edited', + }; + + test('component loads correctly with categories', async () => { + render( + + + + + + + + + , + ); + await wait(); + + await waitFor(() => { + expect( + screen.queryByText(translations.noAgendaCategories), + ).not.toBeInTheDocument(); + }); + }); + + test('component loads correctly with no agenda Categories', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.queryByText(translations.noAgendaCategories), + ).toBeInTheDocument(); + }); + }); + + test('opens and closes the update modal correctly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('editAgendCategoryModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('editAgendCategoryModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('updateAgendaCategoryModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('updateAgendaCategoryModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('updateAgendaCategoryModalCloseBtn'), + ); + }); + + test('opens and closes the preview modal correctly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('previewAgendaCategoryModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('previewAgendaCategoryModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('previewAgendaCategoryModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('previewAgendaCategoryModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('previewAgendaCategoryModalCloseBtn'), + ); + }); + + test('opens and closes the update and delete modals through the preview modal', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('previewAgendaCategoryModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('previewAgendaCategoryModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('previewAgendaCategoryModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + await waitFor(() => { + expect( + screen.getByTestId('deleteAgendaCategoryModalBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteAgendaCategoryModalBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('deleteAgendaCategoryCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteAgendaCategoryCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('deleteAgendaCategoryCloseBtn'), + ); + + await waitFor(() => { + expect( + screen.getByTestId('editAgendaCategoryPreviewModalBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('editAgendaCategoryPreviewModalBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('updateAgendaCategoryModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('updateAgendaCategoryModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('updateAgendaCategoryModalCloseBtn'), + ); + }); + + test('updates an agenda category and toasts success', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('editAgendCategoryModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('editAgendCategoryModalBtn')[0]); + + const name = screen.getByPlaceholderText(translations.name); + const description = screen.getByPlaceholderText(translations.description); + + fireEvent.change(name, { target: { value: '' } }); + userEvent.type(name, formData.name); + + fireEvent.change(description, { target: { value: '' } }); + userEvent.type(description, formData.description); + + await waitFor(() => { + expect(screen.getByTestId('editAgendaCategoryBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('editAgendaCategoryBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.agendaCategoryUpdated); + }); + }); + + test('toasts error on unsuccessful updation', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('editAgendCategoryModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('editAgendCategoryModalBtn')[0]); + + const nameInput = screen.getByLabelText(translations.name); + const descriptionInput = screen.getByLabelText(translations.description); + fireEvent.change(nameInput, { target: { value: '' } }); + fireEvent.change(descriptionInput, { + target: { value: '' }, + }); + userEvent.type(nameInput, formData.name); + userEvent.type(descriptionInput, formData.description); + + await waitFor(() => { + expect(screen.getByTestId('editAgendaCategoryBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('editAgendaCategoryBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); + + test('deletes the agenda category and toasts success', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('previewAgendaCategoryModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('previewAgendaCategoryModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('previewAgendaCategoryModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + await waitFor(() => { + expect( + screen.getByTestId('deleteAgendaCategoryModalBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteAgendaCategoryModalBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('deleteAgendaCategoryCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('deleteAgendaCategoryBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.agendaCategoryDeleted); + }); + }); + + test('toasts error on unsuccessful deletion', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('previewAgendaCategoryModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('previewAgendaCategoryModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('previewAgendaCategoryModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + await waitFor(() => { + expect( + screen.getByTestId('deleteAgendaCategoryModalBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteAgendaCategoryModalBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('deleteAgendaCategoryCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteAgendaCategoryBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/components/AgendaCategory/AgendaCategoryContainer.tsx b/src/components/AgendaCategory/AgendaCategoryContainer.tsx new file mode 100644 index 0000000000..e803e77172 --- /dev/null +++ b/src/components/AgendaCategory/AgendaCategoryContainer.tsx @@ -0,0 +1,272 @@ +import React, { useState } from 'react'; +import type { ChangeEvent } from 'react'; +import { Button, Col, Row } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; +import { useMutation } from '@apollo/client'; + +import { + DELETE_AGENDA_ITEM_CATEGORY_MUTATION, + UPDATE_AGENDA_ITEM_CATEGORY_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import type { InterfaceAgendaItemCategoryInfo } from 'utils/interfaces'; +import styles from './AgendaCategoryContainer.module.css'; + +import AgendaCategoryDeleteModal from 'screens/OrganizationAgendaCategory/AgendaCategoryDeleteModal'; +import AgendaCategoryPreviewModal from 'screens/OrganizationAgendaCategory/AgendaCategoryPreviewModal'; +import AgendaCategoryUpdateModal from 'screens/OrganizationAgendaCategory/AgendaCategoryUpdateModal'; + +function agendaCategoryContainer({ + agendaCategoryConnection, + agendaCategoryData, + agendaCategoryRefetch, +}: { + agendaCategoryConnection: 'Organization'; + agendaCategoryData: InterfaceAgendaItemCategoryInfo[] | undefined; + agendaCategoryRefetch: () => void; +}): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'organizationAgendaCategory', + }); + const { t: tCommon } = useTranslation('common'); + const [ + agendaCategoryPreviewModalIsOpen, + setAgendaCategoryPreviewModalIsOpen, + ] = useState(false); + const [agendaCategoryUpdateModalIsOpen, setAgendaCategoryUpdateModalIsOpen] = + useState(false); + const [agendaCategoryDeleteModalIsOpen, setAgendaCategoryDeleteModalIsOpen] = + useState(false); + + const [agendaCategoryId, setAgendaCategoryId] = useState(''); + + const [formState, setFormState] = useState({ + name: '', + description: '', + createdBy: '', + }); + + const showPreviewModal = ( + agendaItemCategory: InterfaceAgendaItemCategoryInfo, + ): void => { + setAgendaCategoryState(agendaItemCategory); + setAgendaCategoryPreviewModalIsOpen(true); + }; + + const hidePreviewModal = (): void => { + setAgendaCategoryPreviewModalIsOpen(false); + }; + + const showUpdateModal = (): void => { + setAgendaCategoryUpdateModalIsOpen(!agendaCategoryUpdateModalIsOpen); + }; + + const hideUpdateModal = (): void => { + setAgendaCategoryUpdateModalIsOpen(!agendaCategoryUpdateModalIsOpen); + }; + + const toggleDeleteModal = (): void => { + setAgendaCategoryDeleteModalIsOpen(!agendaCategoryDeleteModalIsOpen); + }; + + const [updateAgendaCategory] = useMutation( + UPDATE_AGENDA_ITEM_CATEGORY_MUTATION, + ); + + const updateAgendaCategoryHandler = async ( + event: ChangeEvent, + ): Promise => { + event.preventDefault(); + try { + await updateAgendaCategory({ + variables: { + updateAgendaCategoryId: agendaCategoryId, + input: { + name: formState.name, + description: formState.description, + }, + }, + }); + + agendaCategoryRefetch(); + hideUpdateModal(); + toast.success(t('agendaCategoryUpdated')); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(`Agenda Category Update Failed ${error.message}`); + } + } + }; + + const [deleteAgendaCategory] = useMutation( + DELETE_AGENDA_ITEM_CATEGORY_MUTATION, + ); + + const deleteAgendaCategoryHandler = async (): Promise => { + try { + await deleteAgendaCategory({ + variables: { + deleteAgendaCategoryId: agendaCategoryId, + }, + }); + agendaCategoryRefetch(); + toggleDeleteModal(); + toast.success(t('agendaCategoryDeleted')); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(`Agenda Category Delete Failed, ${error.message}`); + } + } + }; + + const handleEditClick = ( + agendaItemCategory: InterfaceAgendaItemCategoryInfo, + ): void => { + setAgendaCategoryState(agendaItemCategory); + showUpdateModal(); + }; + + const setAgendaCategoryState = ( + agendaItemCategory: InterfaceAgendaItemCategoryInfo, + ): void => { + setFormState({ + ...formState, + name: `${agendaItemCategory.name} `, + description: `${agendaItemCategory.description}`, + createdBy: `${agendaItemCategory.createdBy.firstName} ${agendaItemCategory.createdBy.lastName}`, + }); + setAgendaCategoryId(agendaItemCategory._id); + }; + + return ( + <> +
+
+ + +
{t('name')}
+ + + {t('description')} + + +
{t('createdBy')}
+ + +
{t('options')}
+ +
+
+
+ {agendaCategoryData?.map((agendaCategory, index) => ( +
+ + + {`${agendaCategory.name}`} + + + {agendaCategory.description} + + + {`${agendaCategory.createdBy.firstName} ${agendaCategory.createdBy.lastName}`} + + + +
+ + +
+ +
+ + {index !== agendaCategoryData.length - 1 && ( +
+ )} +
+ ))} + {agendaCategoryData?.length === 0 && ( +
+ {t('noAgendaCategories')} +
+ )} +
+
+ + {/* Preview model */} + + {/* Update model */} + + {/* Delete model */} + + + ); +} + +export default agendaCategoryContainer; diff --git a/src/components/AgendaCategory/AgendaCategoryContainerMocks.ts b/src/components/AgendaCategory/AgendaCategoryContainerMocks.ts new file mode 100644 index 0000000000..f5dee5cffd --- /dev/null +++ b/src/components/AgendaCategory/AgendaCategoryContainerMocks.ts @@ -0,0 +1,104 @@ +import { + UPDATE_AGENDA_ITEM_CATEGORY_MUTATION, + DELETE_AGENDA_ITEM_CATEGORY_MUTATION, +} from 'GraphQl/Mutations/AgendaCategoryMutations'; + +export const MOCKS = [ + { + request: { + query: UPDATE_AGENDA_ITEM_CATEGORY_MUTATION, + variables: { + updateAgendaCategoryId: 'agendaCategory1', + input: { + name: 'AgendaCategory 1 Edited', + description: 'AgendaCategory 1 Description Edited', + }, + }, + }, + result: { + data: { + updateAgendaCategory: { + _id: 'agendaCategory1', + }, + }, + }, + }, + { + request: { + query: UPDATE_AGENDA_ITEM_CATEGORY_MUTATION, + variables: { + updateAgendaCategoryId: 'agendaCategory1', + input: { + name: 'AgendaCategory 1', + description: 'AgendaCategory 1 Description', + }, + }, + }, + result: { + data: { + updateAgendaCategory: { + _id: 'agendaCategory1', + }, + }, + }, + }, + { + request: { + query: UPDATE_AGENDA_ITEM_CATEGORY_MUTATION, + variables: { + updateAgendaCategoryId: 'agendaCategory2', + input: { + name: 'AgendaCategory 2 edited', + description: 'AgendaCategory 2 Description', + }, + }, + }, + result: { + data: { + updateAgendaCategory: { + _id: 'agendaCategory2', + }, + }, + }, + }, + { + request: { + query: DELETE_AGENDA_ITEM_CATEGORY_MUTATION, + variables: { + deleteAgendaCategoryId: 'agendaCategory1', + }, + }, + result: { + data: { + deleteAgendaCategory: { + _id: 'agendaCategory1', + }, + }, + }, + }, +]; + +export const MOCKS_ERROR_MUTATIONS = [ + { + request: { + query: UPDATE_AGENDA_ITEM_CATEGORY_MUTATION, + variables: { + updateAgendaCategoryId: 'agendaCategory1', + input: { + name: 'AgendaCategory 1 Edited', + description: 'AgendaCategory 1 Description Edited', + }, + }, + }, + error: new Error('Mock Graphql Error'), + }, + { + request: { + query: DELETE_AGENDA_ITEM_CATEGORY_MUTATION, + variables: { + deleteAgendaCategoryId: 'agendaCategory1', + }, + }, + error: new Error('Mock Graphql Error'), + }, +]; diff --git a/src/components/AgendaCategory/AgendaCategoryContainerProps.ts b/src/components/AgendaCategory/AgendaCategoryContainerProps.ts new file mode 100644 index 0000000000..5181eec153 --- /dev/null +++ b/src/components/AgendaCategory/AgendaCategoryContainerProps.ts @@ -0,0 +1,34 @@ +type AgendaCategoryConnectionType = 'Organization'; + +export const props = { + agendaCategoryConnection: 'Organization' as AgendaCategoryConnectionType, + agendaCategoryData: [ + { + _id: 'agendaCategory1', + name: 'AgendaCategory 1', + description: 'AgendaCategory 1 Description', + createdBy: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + { + _id: 'agendaCategory2', + name: 'AgendaCategory 2', + description: 'AgendaCategory 2 Description', + createdBy: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + ], + agendaCategoryRefetch: jest.fn(), +}; + +export const props2 = { + agendaCategoryConnection: 'Organization' as AgendaCategoryConnectionType, + agendaCategoryData: [], + agendaCategoryRefetch: jest.fn(), +}; diff --git a/src/components/AgendaItems/AgendaItemsContainer.module.css b/src/components/AgendaItems/AgendaItemsContainer.module.css new file mode 100644 index 0000000000..f254e7aad7 --- /dev/null +++ b/src/components/AgendaItems/AgendaItemsContainer.module.css @@ -0,0 +1,230 @@ +.createModal { + margin-top: 20vh; + margin-left: 13vw; + max-width: 80vw; +} + +.titlemodal { + color: var(--bs-gray-600); + font-weight: 600; + font-size: 20px; + margin-bottom: 20px; + padding-bottom: 5px; + border-bottom: 3px solid var(--bs-primary); + width: 65%; +} + +.agendaItemsOptionsButton { + width: 24px; + height: 24px; +} + +.agendaItemModal { + max-width: 80vw; + margin-top: 2vh; + margin-left: 13vw; +} + +.iconContainer { + display: flex; + justify-content: flex-end; +} +.icon { + margin: 1px; +} + +.errorIcon { + transform: scale(1.5); + color: var(--bs-danger); + margin-bottom: 1rem; +} + +.greenregbtn { + margin: 1rem 0 0; + margin-top: 15px; + 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%; +} + +.preview { + display: flex; + flex-direction: row; + font-weight: 900; + font-size: 16px; + color: rgb(80, 80, 80); +} + +.view { + margin-left: 2%; + font-weight: 600; + font-size: 16px; + color: var(--bs-gray-600); +} + +.previewFile { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + margin-top: 10px; +} + +.previewFile img, +.previewFile video { + width: 100%; + max-width: 400px; + height: auto; + margin-bottom: 10px; +} + +.attachmentPreview { + position: relative; + width: 100%; +} + +.closeButtonFile { + position: absolute; + top: 10px; + right: 10px; + background: transparent; + transform: scale(1.2); + cursor: pointer; + border: none; + color: #707070; + font-weight: 600; + font-size: 16px; + cursor: pointer; +} + +.tableHeader { + background-color: var(--bs-primary); + color: var(--bs-white); + font-size: 16px; +} + +.noOutline input { + outline: none; +} + +.categoryContainer { + display: flex; + flex-wrap: wrap; + gap: 10px; + justify-content: center; +} + +.categoryChip { + display: inline-flex; + align-items: center; + background-color: #e0e0e0; + border-radius: 16px; + padding: 0 12px; + font-size: 14px; + height: 32px; + margin: 5px; +} + +.urlListItem { + display: flex; + align-items: center; + justify-content: space-between; + padding: 5px 0; +} + +.urlIcon { + margin-right: 10px; +} + +.deleteButton { + margin-left: auto; + padding: 2px 5px; +} + +.urlListItem a { + text-decoration: none; + color: inherit; +} + +.urlListItem a:hover { + text-decoration: underline; +} + +.agendaItemRow { + border: 1px solid #dee2e6; + border-radius: 4px; + transition: box-shadow 0.2s ease; + background-color: #fff; +} +.agendaItemRow:hover { + background-color: #f0f0f0; +} + +.dragging { + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); + z-index: 1000; + background-color: #f0f0f0; +} + +.droppable { + background-color: #f9f9f9; /* Background color of droppable area */ +} + +.droppableDraggingOver { + background-color: #e6f7ff; /* Background color of droppable area while dragging over */ +} + +.tableHead { + background-color: #31bb6b !important; + color: white; + border-radius: 20px 20px 0px 0px !important; + padding: 20px; +} + +@media (max-width: 768px) { + .createModal, + .agendaItemModal { + margin: 10vh auto; + max-width: 90%; + } + + .titlemodal { + width: 90%; + } + + .greenregbtn { + width: 90%; + } + + /* Add more specific styles for smaller screens as needed */ +} + +@media (max-width: 576px) { + .createModal, + .agendaItemModal { + margin: 5vh auto; + max-width: 95%; + } + + .titlemodal { + width: 100%; + } + + .greenregbtn { + width: 100%; + } + + /* Additional specific styles for even smaller screens */ +} diff --git a/src/components/AgendaItems/AgendaItemsContainer.test.tsx b/src/components/AgendaItems/AgendaItemsContainer.test.tsx new file mode 100644 index 0000000000..cb514bbfb9 --- /dev/null +++ b/src/components/AgendaItems/AgendaItemsContainer.test.tsx @@ -0,0 +1,418 @@ +import React from 'react'; +import { + render, + screen, + waitFor, + act, + waitForElementToBeRemoved, + 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'; +import i18nForTest from 'utils/i18nForTest'; +import { toast } from 'react-toastify'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; + +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; + +import { props, props2 } from './AgendaItemsContainerProps'; +import { MOCKS, MOCKS_ERROR } from './AgendaItemsContainerMocks'; +import AgendaItemsContainer from './AgendaItemsContainer'; + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(MOCKS_ERROR, true); + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +async function wait(ms = 100): Promise { + await act(async () => { + return new Promise((resolve) => setTimeout(resolve, ms)); + }); +} + +const translations = JSON.parse( + JSON.stringify(i18nForTest.getDataByLanguage('en')?.translation.agendaItems), +); + +describe('Testing Agenda Items components', () => { + const formData = { + title: 'AgendaItem 1 Edited', + description: 'AgendaItem 1 Description Edited', + }; + + test('component loads correctly with items', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.queryByText(translations.noAgendaItems), + ).not.toBeInTheDocument(); + }); + }); + + test('component loads correctly with no agenda items', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.queryByText(translations.noAgendaItems), + ).toBeInTheDocument(); + }); + }); + + test('opens and closes the update modal correctly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('editAgendaItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('editAgendaItemModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('updateAgendaItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('updateAgendaItemModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('updateAgendaItemModalCloseBtn'), + ); + }); + + test('opens and closes the preview modal correctly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('previewAgendaItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('previewAgendaItemModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('previewAgendaItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('previewAgendaItemModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('previewAgendaItemModalCloseBtn'), + ); + }); + + test('opens and closes the update and delete modals through the preview modal', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('previewAgendaItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('previewAgendaItemModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('previewAgendaItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + await waitFor(() => { + expect( + screen.getByTestId('previewAgendaItemModalDeleteBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('previewAgendaItemModalDeleteBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('deleteAgendaItemCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteAgendaItemCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('deleteAgendaItemCloseBtn'), + ); + + await waitFor(() => { + expect( + screen.getByTestId('previewAgendaItemModalUpdateBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('previewAgendaItemModalUpdateBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('updateAgendaItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('updateAgendaItemModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('updateAgendaItemModalCloseBtn'), + ); + }); + + test('updates an agenda Items and toasts success', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('editAgendaItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('editAgendaItemModalBtn')[0]); + + const title = screen.getByPlaceholderText(translations.enterTitle); + const description = screen.getByPlaceholderText( + translations.enterDescription, + ); + + fireEvent.change(title, { target: { value: '' } }); + userEvent.type(title, formData.title); + + fireEvent.change(description, { target: { value: '' } }); + userEvent.type(description, formData.description); + + await waitFor(() => { + expect(screen.getByTestId('updateAgendaItemBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('updateAgendaItemBtn')); + + await waitFor(() => { + // expect(toast.success).toBeCalledWith(translations.agendaItemUpdated); + }); + }); + + test('toasts error on unsuccessful updation', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('editAgendaItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('editAgendaItemModalBtn')[0]); + + const titleInput = screen.getByLabelText(translations.title); + const descriptionInput = screen.getByLabelText(translations.description); + fireEvent.change(titleInput, { target: { value: '' } }); + fireEvent.change(descriptionInput, { + target: { value: '' }, + }); + userEvent.type(titleInput, formData.title); + userEvent.type(descriptionInput, formData.description); + + await waitFor(() => { + expect(screen.getByTestId('updateAgendaItemBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('updateAgendaItemBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); + + test('deletes the agenda item and toasts success', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('previewAgendaItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('previewAgendaItemModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('previewAgendaItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + await waitFor(() => { + expect( + screen.getByTestId('previewAgendaItemModalDeleteBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('previewAgendaItemModalDeleteBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('deleteAgendaItemCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('deleteAgendaItemBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.agendaItemDeleted); + }); + }); + + test('toasts error on unsuccessful deletion', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('previewAgendaItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('previewAgendaItemModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('previewAgendaItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + await waitFor(() => { + expect( + screen.getByTestId('previewAgendaItemModalDeleteBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('previewAgendaItemModalDeleteBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('deleteAgendaItemCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteAgendaItemBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); + + // write test case for drag and drop line:- 172-202 +}); diff --git a/src/components/AgendaItems/AgendaItemsContainer.tsx b/src/components/AgendaItems/AgendaItemsContainer.tsx new file mode 100644 index 0000000000..5b3a00b139 --- /dev/null +++ b/src/components/AgendaItems/AgendaItemsContainer.tsx @@ -0,0 +1,411 @@ +import React, { useState } from 'react'; +import type { ChangeEvent } from 'react'; +import { Button, Col, Row } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; +import { useMutation } from '@apollo/client'; +import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd'; +import type { DropResult } from 'react-beautiful-dnd'; + +import { + DELETE_AGENDA_ITEM_MUTATION, + UPDATE_AGENDA_ITEM_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import type { + InterfaceAgendaItemInfo, + InterfaceAgendaItemCategoryInfo, +} from 'utils/interfaces'; +import styles from './AgendaItemsContainer.module.css'; + +import AgendaItemsPreviewModal from 'components/AgendaItems/AgendaItemsPreviewModal'; +import AgendaItemsDeleteModal from 'components/AgendaItems/AgendaItemsDeleteModal'; +import AgendaItemsUpdateModal from 'components/AgendaItems/AgendaItemsUpdateModal'; + +function AgendaItemsContainer({ + agendaItemConnection, + agendaItemData, + agendaItemRefetch, + agendaItemCategories, +}: { + agendaItemConnection: 'Event'; + agendaItemData: InterfaceAgendaItemInfo[] | undefined; + agendaItemRefetch: () => void; + agendaItemCategories: InterfaceAgendaItemCategoryInfo[] | undefined; +}): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'agendaItems', + }); + const { t: tCommon } = useTranslation('common'); + + const [agendaItemPreviewModalIsOpen, setAgendaItemPreviewModalIsOpen] = + useState(false); + const [agendaItemUpdateModalIsOpen, setAgendaItemUpdateModalIsOpen] = + useState(false); + const [agendaItemDeleteModalIsOpen, setAgendaItemDeleteModalIsOpen] = + useState(false); + + const [agendaItemId, setAgendaItemId] = useState(''); + + const [formState, setFormState] = useState<{ + agendaItemCategoryIds: string[]; + agendaItemCategoryNames: string[]; + title: string; + description: string; + duration: string; + attachments: string[]; + urls: string[]; + createdBy: { + firstName: string; + lastName: string; + }; + }>({ + agendaItemCategoryIds: [], + agendaItemCategoryNames: [], + title: '', + description: '', + duration: '', + attachments: [], + urls: [], + createdBy: { + firstName: '', + lastName: '', + }, + }); + + const showPreviewModal = (agendaItem: InterfaceAgendaItemInfo): void => { + setAgendaItemState(agendaItem); + setAgendaItemPreviewModalIsOpen(true); + }; + + const hidePreviewModal = (): void => { + setAgendaItemPreviewModalIsOpen(false); + }; + + const showUpdateModal = (): void => { + setAgendaItemUpdateModalIsOpen(!agendaItemUpdateModalIsOpen); + }; + + const hideUpdateModal = (): void => { + setAgendaItemUpdateModalIsOpen(!agendaItemUpdateModalIsOpen); + }; + + const toggleDeleteModal = (): void => { + setAgendaItemDeleteModalIsOpen(!agendaItemDeleteModalIsOpen); + }; + + const [updateAgendaItem] = useMutation(UPDATE_AGENDA_ITEM_MUTATION); + + const updateAgendaItemHandler = async ( + e: ChangeEvent, + ): Promise => { + e.preventDefault(); + try { + await updateAgendaItem({ + variables: { + updateAgendaItemId: agendaItemId, + input: { + title: formState.title, + description: formState.description, + duration: formState.duration, + categories: formState.agendaItemCategoryIds, + attachments: formState.attachments, + urls: formState.urls, + }, + }, + }); + agendaItemRefetch(); + hideUpdateModal(); + toast.success(t('agendaItemUpdated')); + } catch (error) { + if (error instanceof Error) { + toast.error(`${error.message}`); + } + } + }; + + const [deleteAgendaItem] = useMutation(DELETE_AGENDA_ITEM_MUTATION); + + const deleteAgendaItemHandler = async (): Promise => { + try { + await deleteAgendaItem({ + variables: { + removeAgendaItemId: agendaItemId, + }, + }); + agendaItemRefetch(); + toggleDeleteModal(); + toast.success(t('agendaItemDeleted')); + } catch (error) { + if (error instanceof Error) { + toast.error(`${error.message}`); + } + } + }; + + const handleEditClick = (agendaItem: InterfaceAgendaItemInfo): void => { + setAgendaItemState(agendaItem); + showUpdateModal(); + }; + + const setAgendaItemState = (agendaItem: InterfaceAgendaItemInfo): void => { + setFormState({ + ...formState, + agendaItemCategoryIds: agendaItem.categories.map( + (category) => category._id, + ), + agendaItemCategoryNames: agendaItem.categories.map( + (category) => category.name, + ), + title: agendaItem.title, + description: agendaItem.description, + duration: agendaItem.duration, + attachments: agendaItem.attachments, + urls: agendaItem.urls, + createdBy: { + firstName: agendaItem.createdBy.firstName, + lastName: agendaItem.createdBy.lastName, + }, + }); + setAgendaItemId(agendaItem._id); + }; + + const onDragEnd = async (result: DropResult): Promise => { + if (!result.destination || !agendaItemData) { + return; + } + + const reorderedAgendaItems = Array.from(agendaItemData); + const [removed] = reorderedAgendaItems.splice(result.source.index, 1); + reorderedAgendaItems.splice(result.destination.index, 0, removed); + + try { + await Promise.all( + reorderedAgendaItems.map(async (item, index) => { + if (item.sequence !== index + 1) { + // Only update if the sequence has changed + await updateAgendaItem({ + variables: { + updateAgendaItemId: item._id, + input: { + sequence: index + 1, // Update sequence based on new index + }, + }, + }); + } + }), + ); + + // After updating all items, refetch data and notify success + agendaItemRefetch(); + } catch (error) { + if (error instanceof Error) { + toast.error(`${error.message}`); + } + } + }; + + return ( + <> +
+
+ + +
{t('sequence')}
+ + + {t('title')} + + + {t('category')} + + + {t('description')} + + +
{t('options')}
+ +
+
+ + + {(provided) => ( +
+ {agendaItemData && + agendaItemData.map((agendaItem, index) => ( + + {(provided, snapshot) => ( +
+ + + + + + {agendaItem.title} + + +
+ {agendaItem.categories.length > 0 ? ( + agendaItem.categories.map((category, idx) => ( + + {category.name} + {idx < agendaItem.categories.length - 1 && + ', '} + + )) + ) : ( + + No Category + + )} +
+ {' '} + + {agendaItem.description} + + +
+ + +
+ +
+
+ )} +
+ ))} + {agendaItemData?.length === 0 && ( +
+ {t('noAgendaItems')} +
+ )} +
+ )} +
+
+
+ {/* Preview model */} + + {/* Delete model */} + + {/* Update model */} + + + ); +} + +export default AgendaItemsContainer; diff --git a/src/components/AgendaItems/AgendaItemsContainerMocks.ts b/src/components/AgendaItems/AgendaItemsContainerMocks.ts new file mode 100644 index 0000000000..11cd8b254e --- /dev/null +++ b/src/components/AgendaItems/AgendaItemsContainerMocks.ts @@ -0,0 +1,119 @@ +import { + UPDATE_AGENDA_ITEM_MUTATION, + DELETE_AGENDA_ITEM_MUTATION, +} from 'GraphQl/Mutations/AgendaItemMutations'; + +export const MOCKS = [ + { + request: { + query: UPDATE_AGENDA_ITEM_MUTATION, + variables: { + updateAgendaItemId: 'agendaItem1', + input: { + title: 'AgendaItem 1 Edited', + description: 'AgendaItem 1 Description Edited', + }, + }, + }, + result: { + data: { + updateAgendaItem: { + _id: 'agendaItem1', + }, + }, + }, + }, + { + request: { + query: UPDATE_AGENDA_ITEM_MUTATION, + variables: { + updateAgendaItemId: 'agendaItem1', + input: { + title: 'AgendaItem 1', + description: 'AgendaItem 1 Description', + }, + }, + }, + result: { + data: { + updateAgendaItem: { + _id: 'agendaItem1', + }, + }, + }, + }, + { + request: { + query: UPDATE_AGENDA_ITEM_MUTATION, + variables: { + updateAgendaItemId: 'agendaItem2', + input: { + title: 'AgendaItem 2 edited', + description: 'AgendaItem 2 Description', + }, + }, + }, + result: { + data: { + updateAgendaItem: { + _id: 'agendaItem2', + }, + }, + }, + }, + { + request: { + query: DELETE_AGENDA_ITEM_MUTATION, + variables: { + removeAgendaItemId: 'agendaItem1', + }, + }, + result: { + data: { + removeAgendaItem: { + _id: 'agendaItem1', + }, + }, + }, + }, + { + request: { + query: DELETE_AGENDA_ITEM_MUTATION, + variables: { + removeAgendaItemId: 'agendaItem2', + }, + }, + result: { + data: { + removeAgendaItem: { + _id: 'agendaItem2', + }, + }, + }, + }, +]; + +export const MOCKS_ERROR = [ + { + request: { + query: UPDATE_AGENDA_ITEM_MUTATION, + variables: { + updateAgendaItemId: 'agendaItem1', + input: { + title: 'AgendaItem 1 Edited', + description: 'AgendaItem 1 Description Edited', + }, + }, + }, + error: new Error('An error occurred'), + }, + { + request: { + query: DELETE_AGENDA_ITEM_MUTATION, + variables: { + removeAgendaItemId: 'agendaItem1', + }, + }, + error: new Error('An error occurred'), + }, +]; diff --git a/src/components/AgendaItems/AgendaItemsContainerProps.ts b/src/components/AgendaItems/AgendaItemsContainerProps.ts new file mode 100644 index 0000000000..d6dcf3feca --- /dev/null +++ b/src/components/AgendaItems/AgendaItemsContainerProps.ts @@ -0,0 +1,101 @@ +type AgendaItemConnectionType = 'Event'; + +export const props = { + agendaItemConnection: 'Event' as AgendaItemConnectionType, + agendaItemData: [ + { + _id: 'agendaItem1', + title: 'AgendaItem 1', + description: 'AgendaItem 1 Description', + duration: '2h', + attachments: ['attachment1'], + createdBy: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + urls: [], + users: [], + sequence: 1, + categories: [ + { + _id: 'category1', + name: 'Category 1', + }, + ], + organization: { + _id: 'org1', + name: 'Unity Foundation', + }, + relatedEvent: { + _id: 'event1', + title: 'Aerobics for Everyone', + }, + }, + { + _id: 'agendaItem2', + title: 'AgendaItem 2', + description: 'AgendaItem 2 Description', + duration: '1h', + attachments: ['attachment3'], + createdBy: { + _id: 'user1', + firstName: 'Jane', + lastName: 'Doe', + }, + urls: ['http://example.com'], + users: [ + { + _id: 'user2', + firstName: 'John', + lastName: 'Smith', + }, + ], + sequence: 2, + categories: [ + { + _id: 'category2', + name: 'Category 2', + }, + ], + organization: { + _id: 'org2', + name: 'Health Organization', + }, + relatedEvent: { + _id: 'event2', + title: 'Yoga for Beginners', + }, + }, + ], + agendaItemRefetch: jest.fn(), + agendaItemCategories: [ + { + _id: 'agendaCategory1', + name: 'AgendaCategory 1', + description: 'AgendaCategory 1 Description', + createdBy: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + { + _id: 'agendaCategory2', + name: 'AgendaCategory 2', + description: 'AgendaCategory 2 Description', + createdBy: { + _id: 'user1', + firstName: 'Jane', + lastName: 'Doe', + }, + }, + ], +}; + +export const props2 = { + agendaItemConnection: 'Event' as AgendaItemConnectionType, + agendaItemData: [], + agendaItemRefetch: jest.fn(), + agendaItemCategories: [], +}; diff --git a/src/components/AgendaItems/AgendaItemsCreateModal.test.tsx b/src/components/AgendaItems/AgendaItemsCreateModal.test.tsx new file mode 100644 index 0000000000..5b7339ad67 --- /dev/null +++ b/src/components/AgendaItems/AgendaItemsCreateModal.test.tsx @@ -0,0 +1,368 @@ +import React from 'react'; +import { + render, + screen, + fireEvent, + waitFor, + within, +} from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; + +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; + +import AgendaItemsCreateModal from './AgendaItemsCreateModal'; +import { toast } from 'react-toastify'; +import convertToBase64 from 'utils/convertToBase64'; + +const mockFormState = { + title: 'Test Title', + description: 'Test Description', + duration: '20', + attachments: ['Test Attachment'], + urls: ['https://example.com'], + agendaItemCategoryIds: ['category'], +}; +const mockHideCreateModal = jest.fn(); +const mockSetFormState = jest.fn(); +const mockCreateAgendaItemHandler = jest.fn(); +const mockT = (key: string): string => key; +const mockAgendaItemCategories = [ + { + _id: '1', + name: 'Test Name', + description: 'Test Description', + createdBy: { + _id: '1', + firstName: 'Test', + lastName: 'User', + }, + }, + { + _id: '2', + name: 'Another Category', + description: 'Another Description', + createdBy: { + _id: '2', + firstName: 'Another', + lastName: 'Creator', + }, + }, + { + _id: '3', + name: 'Third Category', + description: 'Third Description', + createdBy: { + _id: '3', + firstName: 'Third', + lastName: 'User', + }, + }, +]; +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); +jest.mock('utils/convertToBase64'); +const mockedConvertToBase64 = convertToBase64 as jest.MockedFunction< + typeof convertToBase64 +>; + +describe('AgendaItemsCreateModal', () => { + test('renders modal correctly', () => { + render( + + + + + + + + + + + , + ); + + expect(screen.getByText('agendaItemDetails')).toBeInTheDocument(); + expect(screen.getByTestId('createAgendaItemFormBtn')).toBeInTheDocument(); + expect( + screen.getByTestId('createAgendaItemModalCloseBtn'), + ).toBeInTheDocument(); + }); + + test('tests the condition for formState', async () => { + const mockFormState = { + title: 'Test Title', + description: 'Test Description', + duration: '20', + attachments: ['Test Attachment'], + urls: ['https://example.com'], + agendaItemCategoryIds: ['1'], + }; + render( + + + + + + + + + + + , + ); + + fireEvent.change(screen.getByLabelText('title'), { + target: { value: 'New title' }, + }); + + fireEvent.change(screen.getByLabelText('description'), { + target: { value: 'New description' }, + }); + + fireEvent.change(screen.getByLabelText('duration'), { + target: { value: '30' }, + }); + + fireEvent.click(screen.getByTestId('deleteUrl')); + fireEvent.click(screen.getByTestId('deleteAttachment')); + + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + title: 'New title', + }); + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + description: 'New description', + }); + + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + duration: '30', + }); + + await waitFor(() => { + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + urls: [], + }); + }); + + await waitFor(() => { + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + attachments: [], + }); + }); + }); + test('handleAddUrl correctly adds valid URL', async () => { + render( + + + + + + + + + , + ); + + const urlInput = screen.getByTestId('urlInput'); + const linkBtn = screen.getByTestId('linkBtn'); + + fireEvent.change(urlInput, { target: { value: 'https://example.com' } }); + fireEvent.click(linkBtn); + + await waitFor(() => { + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + urls: [...mockFormState.urls, 'https://example.com'], + }); + }); + }); + + test('shows error toast for invalid URL', async () => { + render( + + + + + + + + + + + , + ); + + const urlInput = screen.getByTestId('urlInput'); + const linkBtn = screen.getByTestId('linkBtn'); + + fireEvent.change(urlInput, { target: { value: 'invalid-url' } }); + fireEvent.click(linkBtn); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith('invalidUrl'); + }); + }); + + test('shows error toast for file size exceeding limit', async () => { + render( + + + + + + + + + + + , + ); + + const fileInput = screen.getByTestId('attachment'); + const largeFile = new File( + ['a'.repeat(11 * 1024 * 1024)], + 'large-file.jpg', + ); // 11 MB file + + Object.defineProperty(fileInput, 'files', { + value: [largeFile], + }); + + fireEvent.change(fileInput); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith('fileSizeExceedsLimit'); + }); + }); + + test('adds files correctly when within size limit', async () => { + mockedConvertToBase64.mockResolvedValue('base64-file'); + + render( + + + + + + + + + + + , + ); + + const fileInput = screen.getByTestId('attachment'); + const smallFile = new File(['small-file-content'], 'small-file.jpg'); // Small file + + Object.defineProperty(fileInput, 'files', { + value: [smallFile], + }); + + fireEvent.change(fileInput); + + await waitFor(() => { + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + attachments: [...mockFormState.attachments, 'base64-file'], + }); + }); + }); + test('renders autocomplete and selects categories correctly', async () => { + render( + + + + + + + + + + + , + ); + + const autocomplete = screen.getByTestId('categorySelect'); + expect(autocomplete).toBeInTheDocument(); + + const input = within(autocomplete).getByRole('combobox'); + fireEvent.mouseDown(input); + + const options = screen.getAllByRole('option'); + expect(options).toHaveLength(mockAgendaItemCategories.length); + + fireEvent.click(options[0]); + fireEvent.click(options[1]); + }); +}); diff --git a/src/components/AgendaItems/AgendaItemsCreateModal.tsx b/src/components/AgendaItems/AgendaItemsCreateModal.tsx new file mode 100644 index 0000000000..8506319285 --- /dev/null +++ b/src/components/AgendaItems/AgendaItemsCreateModal.tsx @@ -0,0 +1,293 @@ +import React, { useState, useEffect } from 'react'; +import { Modal, Form, Button, Row, Col } from 'react-bootstrap'; +import { Autocomplete, TextField } from '@mui/material'; + +import { FaLink, FaTrash } from 'react-icons/fa'; +import { toast } from 'react-toastify'; +import styles from './AgendaItemsContainer.module.css'; +import type { ChangeEvent } from 'react'; +import type { InterfaceAgendaItemCategoryInfo } from 'utils/interfaces'; +import convertToBase64 from 'utils/convertToBase64'; + +interface InterfaceFormStateType { + agendaItemCategoryIds: string[]; + title: string; + description: string; + duration: string; + attachments: string[]; + urls: string[]; +} + +interface InterfaceAgendaItemsCreateModalProps { + agendaItemCreateModalIsOpen: boolean; + hideCreateModal: () => void; + formState: InterfaceFormStateType; + setFormState: (state: React.SetStateAction) => void; + createAgendaItemHandler: (e: ChangeEvent) => Promise; + t: (key: string) => string; + agendaItemCategories: InterfaceAgendaItemCategoryInfo[] | undefined; +} + +const AgendaItemsCreateModal: React.FC< + InterfaceAgendaItemsCreateModalProps +> = ({ + agendaItemCreateModalIsOpen, + hideCreateModal, + formState, + setFormState, + createAgendaItemHandler, + t, + agendaItemCategories, +}) => { + const [newUrl, setNewUrl] = useState(''); + + useEffect(() => { + setFormState((prevState) => ({ + ...prevState, + urls: prevState.urls.filter((url) => url.trim() !== ''), + attachments: prevState.attachments.filter((att) => att !== ''), + })); + }, []); + + // Function to validate URL + const isValidUrl = (url: string): boolean => { + // Regular expression for basic URL validation + const urlRegex = /^(ftp|http|https):\/\/[^ "]+$/; + return urlRegex.test(url); + }; + + const handleAddUrl = (): void => { + if (newUrl.trim() !== '' && isValidUrl(newUrl.trim())) { + setFormState({ + ...formState, + urls: [...formState.urls.filter((url) => url.trim() !== ''), newUrl], + }); + setNewUrl(''); + } else { + toast.error(t('invalidUrl')); + } + }; + + const handleRemoveUrl = (url: string): void => { + setFormState({ + ...formState, + urls: formState.urls.filter((item) => item !== url), + }); + }; + + const handleFileChange = async ( + e: React.ChangeEvent, + ): Promise => { + const target = e.target as HTMLInputElement; + if (target.files) { + const files = Array.from(target.files); + let totalSize = 0; + files.forEach((file) => { + totalSize += file.size; + }); + if (totalSize > 10 * 1024 * 1024) { + toast.error(t('fileSizeExceedsLimit')); + return; + } + const base64Files = await Promise.all( + files.map(async (file) => await convertToBase64(file)), + ); + setFormState({ + ...formState, + attachments: [...formState.attachments, ...base64Files], + }); + } + }; + + const handleRemoveAttachment = (attachment: string): void => { + setFormState({ + ...formState, + attachments: formState.attachments.filter((item) => item !== attachment), + }); + }; + + return ( + + +

{t('agendaItemDetails')}

+ +
+ +
+ + + formState.agendaItemCategoryIds.includes(category._id), + ) || [] + } + // isOptionEqualToValue={(option, value) => option._id === value._id} + filterSelectedOptions={true} + getOptionLabel={( + category: InterfaceAgendaItemCategoryInfo, + ): string => category.name} + onChange={(_, newCategories): void => { + setFormState({ + ...formState, + agendaItemCategoryIds: newCategories.map( + (category) => category._id, + ), + }); + }} + renderInput={(params) => ( + + )} + /> + + + + + {t('title')} + + setFormState({ ...formState, title: e.target.value }) + } + /> + + + + + {t('duration')} + + setFormState({ ...formState, duration: e.target.value }) + } + /> + + + + + {t('description')} + + setFormState({ ...formState, description: e.target.value }) + } + /> + + + + {t('url')} +
+ setNewUrl(e.target.value)} + /> + +
+ + {formState.urls.map((url, index) => ( +
  • + + + {url.length > 50 ? url.substring(0, 50) + '...' : url} + + +
  • + ))} +
    + + {t('attachments')} + + {t('attachmentLimit')} + + {formState.attachments && ( +
    + {formState.attachments.map((attachment, index) => ( +
    + {attachment.includes('video') ? ( + + ) : ( + Attachment preview + )} + +
    + ))} +
    + )} + + +
    +
    + ); +}; + +export default AgendaItemsCreateModal; diff --git a/src/components/AgendaItems/AgendaItemsDeleteModal.tsx b/src/components/AgendaItems/AgendaItemsDeleteModal.tsx new file mode 100644 index 0000000000..5361ca4985 --- /dev/null +++ b/src/components/AgendaItems/AgendaItemsDeleteModal.tsx @@ -0,0 +1,63 @@ +import React from 'react'; +import { Modal, Button } from 'react-bootstrap'; +import styles from './AgendaItemsContainer.module.css'; + +interface InterfaceAgendaItemsDeleteModalProps { + agendaItemDeleteModalIsOpen: boolean; + toggleDeleteModal: () => void; + deleteAgendaItemHandler: () => Promise; + t: (key: string) => string; + tCommon: (key: string) => string; +} + +const AgendaItemsDeleteModal: React.FC< + InterfaceAgendaItemsDeleteModalProps +> = ({ + agendaItemDeleteModalIsOpen, + toggleDeleteModal, + deleteAgendaItemHandler, + t, + tCommon, +}) => { + return ( + + + + {t('deleteAgendaItem')} + + + +

    {t('deleteAgendaItemMsg')}

    +
    + + + + +
    + ); +}; + +export default AgendaItemsDeleteModal; diff --git a/src/components/AgendaItems/AgendaItemsPreviewModal.test.tsx b/src/components/AgendaItems/AgendaItemsPreviewModal.test.tsx new file mode 100644 index 0000000000..0a7b4646ba --- /dev/null +++ b/src/components/AgendaItems/AgendaItemsPreviewModal.test.tsx @@ -0,0 +1,102 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; + +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; + +import AgendaItemsPreviewModal from './AgendaItemsPreviewModal'; + +const mockFormState = { + title: 'Test Title', + description: 'Test Description', + duration: '20', + attachments: [ + 'https://example.com/video.mp4', + 'https://example.com/image.jpg', + ], + urls: [ + 'https://example.com', + 'https://thisisaverylongurlthatexceedsfiftycharacters.com/very/long/path', + ], + agendaItemCategoryIds: ['category'], + agendaItemCategoryNames: ['category'], + createdBy: { + firstName: 'Test', + lastName: 'User', + }, +}; + +const mockT = (key: string): string => key; + +describe('AgendaItemsPreviewModal', () => { + test('check url and attachment links', () => { + render( + + + + + + + + + + + , + ); + + expect(screen.getByText('Test Title')).toBeInTheDocument(); + expect(screen.getByText('Test Description')).toBeInTheDocument(); + expect(screen.getByText('20')).toBeInTheDocument(); + expect(screen.getByText('https://example.com')).toBeInTheDocument(); + + // Check attachments + const videoLink = screen.getByText( + (content, element) => + element?.tagName.toLowerCase() === 'a' && + (element as HTMLAnchorElement)?.href === + 'https://example.com/video.mp4', + ); + expect(videoLink).toBeInTheDocument(); + + const imageLink = screen.getByText( + (content, element) => + element?.tagName.toLowerCase() === 'a' && + (element as HTMLAnchorElement)?.href === + 'https://example.com/image.jpg', + ); + expect(imageLink).toBeInTheDocument(); + + // Check URLs + const shortUrlLink = screen.getByText( + (content, element) => + element?.tagName.toLowerCase() === 'a' && + (element as HTMLAnchorElement)?.href === 'https://example.com/', + ); + expect(shortUrlLink).toBeInTheDocument(); + expect(shortUrlLink).toHaveTextContent('https://example.com'); + + const longUrlLink = screen.getByText( + (content, element) => + element?.tagName.toLowerCase() === 'a' && + (element as HTMLAnchorElement)?.href === + 'https://thisisaverylongurlthatexceedsfiftycharacters.com/very/long/path', + ); + expect(longUrlLink).toBeInTheDocument(); + expect(longUrlLink).toHaveTextContent( + 'https://thisisaverylongurlthatexceedsfiftycharacte...', + ); + }); +}); diff --git a/src/components/AgendaItems/AgendaItemsPreviewModal.tsx b/src/components/AgendaItems/AgendaItemsPreviewModal.tsx new file mode 100644 index 0000000000..fc8cb257a2 --- /dev/null +++ b/src/components/AgendaItems/AgendaItemsPreviewModal.tsx @@ -0,0 +1,151 @@ +import React from 'react'; +import { Modal, Form, Button } from 'react-bootstrap'; +import styles from './AgendaItemsContainer.module.css'; +import { FaLink } from 'react-icons/fa'; + +interface InterfaceFormStateType { + agendaItemCategoryIds: string[]; + agendaItemCategoryNames: string[]; + title: string; + description: string; + duration: string; + attachments: string[]; + urls: string[]; + createdBy: { + firstName: string; + lastName: string; + }; +} + +interface InterfaceAgendaItemsPreviewModalProps { + agendaItemPreviewModalIsOpen: boolean; + hidePreviewModal: () => void; + showUpdateModal: () => void; + toggleDeleteModal: () => void; + formState: InterfaceFormStateType; + t: (key: string) => string; +} + +const AgendaItemsPreviewModal: React.FC< + InterfaceAgendaItemsPreviewModalProps +> = ({ + agendaItemPreviewModalIsOpen, + hidePreviewModal, + showUpdateModal, + toggleDeleteModal, + formState, + t, +}) => { + const renderAttachments = (): JSX.Element[] => { + return formState.attachments.map((attachment, index) => ( +
    + {attachment.includes('video') ? ( + + + + ) : ( + + Attachment preview + + )} +
    + )); + }; + + const renderUrls = (): JSX.Element[] => { + return formState.urls.map((url, index) => ( +
  • + + + {url.length > 50 ? `${url.substring(0, 50)}...` : url} + +
  • + )); + }; + + return ( + + +

    {t('agendaItemDetails')}

    + +
    + +
    +
    +
    +

    {t('category')}

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

    {t('title')}

    + {formState.title} +
    +
    +

    {t('description')}

    + {formState.description} +
    +
    +

    {t('duration')}

    + {formState.duration} +
    +
    +

    {t('createdBy')}

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

    {t('urls')}

    + {renderUrls()} +
    +
    +

    {t('attachments')}

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

    {t('updateAgendaItem')}

    + +
    + +
    + + + formState.agendaItemCategoryIds.includes(category._id), + ) || [] + } + // isOptionEqualToValue={(option, value) => option._id === value._id} + filterSelectedOptions={true} + getOptionLabel={( + category: InterfaceAgendaItemCategoryInfo, + ): string => category.name} + onChange={(_, newCategories): void => { + setFormState({ + ...formState, + agendaItemCategoryIds: newCategories.map( + (category) => category._id, + ), + }); + }} + renderInput={(params) => ( + + )} + /> + + + + + + {t('title')} + + setFormState({ ...formState, title: e.target.value }) + } + /> + + + + + {t('duration')} + + setFormState({ ...formState, duration: e.target.value }) + } + /> + + + + + + {t('description')} + + setFormState({ ...formState, description: e.target.value }) + } + /> + + + + {t('url')} +
    + setNewUrl(e.target.value)} + /> + +
    + + {formState.urls.map((url, index) => ( +
  • + + + {url.length > 50 ? url.substring(0, 50) + '...' : url} + + +
  • + ))} +
    + + {t('attachments')} + + {t('attachmentLimit')} + + {formState.attachments && ( +
    + {formState.attachments.map((attachment, index) => ( +
    + {attachment.includes('video') ? ( + + ) : ( + Attachment preview + )} + +
    + ))} +
    + )} + + +
    +
    + ); +}; + +export default AgendaItemsUpdateModal; diff --git a/src/components/Avatar/Avatar.module.css b/src/components/Avatar/Avatar.module.css new file mode 100644 index 0000000000..2a3190892f --- /dev/null +++ b/src/components/Avatar/Avatar.module.css @@ -0,0 +1,14 @@ +.imageContainer { + width: 56px; + height: 56px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 100%; +} +.imageContainer img { + width: 100%; + height: 100%; + object-fit: cover; + border-radius: 100%; +} diff --git a/src/components/Avatar/Avatar.test.tsx b/src/components/Avatar/Avatar.test.tsx new file mode 100644 index 0000000000..d178c48a4a --- /dev/null +++ b/src/components/Avatar/Avatar.test.tsx @@ -0,0 +1,50 @@ +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 new file mode 100644 index 0000000000..6d4cab405b --- /dev/null +++ b/src/components/Avatar/Avatar.tsx @@ -0,0 +1,45 @@ +import React, { useMemo } from 'react'; +import { createAvatar } from '@dicebear/core'; +import { initials } from '@dicebear/collection'; +import styles from 'components/Avatar/Avatar.module.css'; + +interface InterfaceAvatarProps { + name: string; + alt?: string; + size?: number; + avatarStyle?: string; + dataTestId?: string; + radius?: number; +} + +const Avatar = ({ + name, + alt = 'Dummy Avatar', + size, + avatarStyle, + dataTestId, + radius, +}: InterfaceAvatarProps): JSX.Element => { + const avatar = useMemo(() => { + return createAvatar(initials, { + size: size || 128, + seed: name, + radius: radius || 0, + }).toDataUriSync(); + }, [name, size]); + + const svg = avatar.toString(); + + return ( +
    + {alt} +
    + ); +}; + +export default Avatar; diff --git a/src/components/ChangeLanguageDropdown/ChangeLanguageDropDown.tsx b/src/components/ChangeLanguageDropdown/ChangeLanguageDropDown.tsx new file mode 100644 index 0000000000..e4bda6fd7f --- /dev/null +++ b/src/components/ChangeLanguageDropdown/ChangeLanguageDropDown.tsx @@ -0,0 +1,83 @@ +import React from 'react'; +import { Dropdown } from 'react-bootstrap'; +import i18next from 'i18next'; +import { languages } from 'utils/languages'; +import cookies from 'js-cookie'; +import { UPDATE_USER_MUTATION } from 'GraphQl/Mutations/mutations'; +import { useMutation } from '@apollo/client'; +import useLocalStorage from 'utils/useLocalstorage'; +const { getItem } = useLocalStorage(); + +interface InterfaceChangeLanguageDropDownProps { + parentContainerStyle?: string; + btnStyle?: string; + btnTextStyle?: string; +} + +const ChangeLanguageDropDown = ( + props: InterfaceChangeLanguageDropDownProps, +): JSX.Element => { + const currentLanguageCode = cookies.get('i18next') || 'en'; + const userId = getItem('userId'); + const [updateUser] = useMutation(UPDATE_USER_MUTATION); + + const changeLanguage = async (languageCode: string): Promise => { + if (userId) { + try { + await updateUser({ + variables: { + appLanguageCode: languageCode, + }, + }); + await i18next.changeLanguage(languageCode); + cookies.set('i18next', languageCode); + } catch (error) { + console.log('Error in changing language', error); + } + } + }; + + return ( + + + {languages.map((language, index: number) => ( + + {currentLanguageCode === language.code ? ( + + + {language.name} + + ) : null} + + ))} + + + {languages.map((language, index: number) => ( + => changeLanguage(language.code)} + disabled={currentLanguageCode === language.code} + data-testid={`change-language-btn-${language.code}`} + > + + {language.name} + + ))} + + + ); +}; + +export default ChangeLanguageDropDown; diff --git a/src/components/ChangeLanguageDropdown/ChangeLanguageDropdown.test.tsx b/src/components/ChangeLanguageDropdown/ChangeLanguageDropdown.test.tsx new file mode 100644 index 0000000000..71f01677b4 --- /dev/null +++ b/src/components/ChangeLanguageDropdown/ChangeLanguageDropdown.test.tsx @@ -0,0 +1,158 @@ +import React from 'react'; +import { act, render } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { I18nextProvider } from 'react-i18next'; +import { BrowserRouter } from 'react-router-dom'; +import i18nForTest from 'utils/i18nForTest'; +import { languages } from 'utils/languages'; +import ChangeLanguageDropDown from './ChangeLanguageDropDown'; +import cookies from 'js-cookie'; +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 { Provider } from 'react-redux'; +import { store } from 'state/store'; +const { setItem } = useLocalStorage(); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const MOCKS = [ + { + request: { + query: UPDATE_USER_MUTATION, + variables: { + appLanguageCode: 'fr', + }, + }, + result: { + data: { + updateUserProfile: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: UPDATE_USER_MUTATION, + variables: { + appLanguageCode: 'hi', + }, + }, + error: new Error('An error occurred'), + }, +]; + +const link = new StaticMockLink(MOCKS, true); +describe('Testing Change Language Dropdown', () => { + test('Component Should be rendered properly', async () => { + const { getByTestId } = render( + + + + + + + , + ); + + expect(getByTestId('language-dropdown-container')).toBeInTheDocument(); + expect(getByTestId('language-dropdown-btn')).toBeInTheDocument(); + expect(getByTestId('dropdown-btn-0')).toBeInTheDocument(); + + getByTestId('language-dropdown-container').className.includes(''); + getByTestId('language-dropdown-btn').className.includes(''); + getByTestId('dropdown-btn-0').className.includes(''); + + userEvent.click(getByTestId('dropdown-btn-0')); + await wait(); + + languages.map((language) => { + expect( + getByTestId(`change-language-btn-${language.code}`), + ).toBeInTheDocument(); + }); + }); + + test('Component Should accept props properly', async () => { + const props = { + parentContainerStyle: 'parentContainerStyle', + btnStyle: 'btnStyle', + btnTextStyle: 'btnTextStyle', + }; + const { getByTestId } = render( + + + + + + + , + ); + getByTestId('language-dropdown-container').className.includes( + props.parentContainerStyle, + ); + getByTestId('language-dropdown-btn').className.includes(props.btnStyle); + getByTestId('dropdown-btn-0').className.includes(props.btnTextStyle); + }); + + test('Testing when language cookie is not set', async () => { + Object.defineProperty(window.document, 'cookie', { + writable: true, + value: 'i18next=', + }); + + render( + + + + + , + ); + + await wait(); + expect(cookies.get('i18next')).toBe(''); + }); + + test('Testing change language functionality', async () => { + Object.defineProperty(window.document, 'cookie', { + writable: true, + value: 'i18next=sp', + }); + setItem('userId', '1'); + + const { getByTestId } = render( + + + + + , + ); + + userEvent.click(getByTestId('language-dropdown-btn')); + await wait(); + const changeLanguageBtn = getByTestId(`change-language-btn-fr`); + await wait(); + expect(changeLanguageBtn).toBeInTheDocument(); + await wait(); + userEvent.click(changeLanguageBtn); + await wait(); + expect(cookies.get('i18next')).toBe('fr'); + await wait(); + userEvent.click(getByTestId('language-dropdown-btn')); + await wait(); + const changeLanguageBtnHi = getByTestId(`change-language-btn-hi`); + await wait(); + expect(changeLanguageBtnHi).toBeInTheDocument(); + await wait(); + userEvent.click(changeLanguageBtnHi); + await wait(); + }); +}); diff --git a/src/components/CheckIn/CheckInModal.module.css b/src/components/CheckIn/CheckInModal.module.css new file mode 100644 index 0000000000..0f78d81c01 --- /dev/null +++ b/src/components/CheckIn/CheckInModal.module.css @@ -0,0 +1,43 @@ +.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/components/CheckIn/CheckInModal.test.tsx b/src/components/CheckIn/CheckInModal.test.tsx new file mode 100644 index 0000000000..1660c7c4bb --- /dev/null +++ b/src/components/CheckIn/CheckInModal.test.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { fireEvent, render, waitFor } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { CheckInModal } from './CheckInModal'; +import { BrowserRouter } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import { I18nextProvider } from 'react-i18next'; +import i18nForTest from 'utils/i18nForTest'; +import { ToastContainer } from 'react-toastify'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { checkInQueryMock } from './mocks'; +import { StaticMockLink } from 'utils/StaticMockLink'; + +const link = new StaticMockLink(checkInQueryMock, true); + +describe('Testing Check In Attendees Modal', () => { + const props = { + show: true, + eventId: 'event123', + handleClose: jest.fn(), + }; + + 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( + + + + + + + + + + + + , + ); + + await waitFor(() => + expect(queryByText('Event Check In Management')).toBeInTheDocument(), + ); + + await waitFor(() => expect(queryByText('John Doe')).toBeInTheDocument()); + await waitFor(() => expect(queryByText('John2 Doe2')).toBeInTheDocument()); + + // Tetst filtering of users + fireEvent.change(queryByLabelText('Search Attendees') as Element, { + target: { value: 'John Doe' }, + }); + + await waitFor(() => expect(queryByText('John Doe')).toBeInTheDocument()); + await waitFor(() => + expect(queryByText('John2 Doe2')).not.toBeInTheDocument(), + ); + }); +}); diff --git a/src/components/CheckIn/CheckInModal.tsx b/src/components/CheckIn/CheckInModal.tsx new file mode 100644 index 0000000000..6b4e5425c0 --- /dev/null +++ b/src/components/CheckIn/CheckInModal.tsx @@ -0,0 +1,121 @@ +import React, { useState, useEffect } from 'react'; +import { Modal } from 'react-bootstrap'; +import { useQuery } from '@apollo/client'; +import { EVENT_CHECKINS } from 'GraphQl/Queries/Queries'; +import styles from 'components/CheckIn/CheckInModal.module.css'; +import { TableRow } from './TableRow'; +import type { + InterfaceAttendeeCheckIn, + InterfaceModalProp, + InterfaceTableData, +} from './types'; +import type { GridColDef, GridRowHeightReturnValue } from '@mui/x-data-grid'; +import { DataGrid } from '@mui/x-data-grid'; +import TextField from '@mui/material/TextField'; + +export const CheckInModal = (props: InterfaceModalProp): JSX.Element => { + const [tableData, setTableData] = useState([]); + + const [userFilterQuery, setUserFilterQuery] = useState(''); + const [filterQueryModel, setFilterQueryModel] = useState({ + items: [{ field: 'userName', operator: 'contains', value: '' }], + }); + + const { + data: checkInData, + loading: checkInLoading, + refetch: checkInRefetch, + } = useQuery(EVENT_CHECKINS, { + variables: { id: props.eventId }, + }); + + useEffect(() => { + checkInRefetch(); + if (checkInLoading) setTableData([]); + else + setTableData( + checkInData.event.attendeesCheckInStatus.map( + (checkIn: InterfaceAttendeeCheckIn) => ({ + userName: `${checkIn.user.firstName} ${checkIn.user.lastName}`, + id: checkIn._id, + checkInData: { + id: checkIn._id, + name: `${checkIn.user.firstName} ${checkIn.user.lastName}`, + userId: checkIn.user._id, + checkIn: checkIn.checkIn, + eventId: props.eventId, + }, + }), + ), + ); + }, [checkInData, props.eventId, checkInLoading]); + + const columns: GridColDef[] = [ + { field: 'userName', headerName: 'User', width: 300 }, + { + field: 'checkInData', + headerName: 'Check In Status', + width: 400, + renderCell: (props) => ( + + ), + }, + ]; + + // Render the loading screen + if (checkInLoading) { + return ( + <> +
    + + ); + } + return ( + <> + + + + Event Check In Management + + + +
    + { + setUserFilterQuery(e.target.value); + setFilterQueryModel({ + items: [ + { + field: 'userName', + operator: 'contains', + value: e.target.value, + }, + ], + }); + }} + fullWidth + /> +
    +
    + 'auto'} + columns={columns} + filterModel={filterQueryModel} + /> +
    +
    +
    + + ); +}; diff --git a/src/components/CheckIn/CheckInWrapper.module.css b/src/components/CheckIn/CheckInWrapper.module.css new file mode 100644 index 0000000000..f5f42546c3 --- /dev/null +++ b/src/components/CheckIn/CheckInWrapper.module.css @@ -0,0 +1,13 @@ +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.test.tsx new file mode 100644 index 0000000000..81f53d0043 --- /dev/null +++ b/src/components/CheckIn/CheckInWrapper.test.tsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { CheckInWrapper } from './CheckInWrapper'; +import { BrowserRouter } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import { I18nextProvider } from 'react-i18next'; +import i18nForTest from 'utils/i18nForTest'; +import { ToastContainer } from 'react-toastify'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { checkInQueryMock } from './mocks'; +import { StaticMockLink } from 'utils/StaticMockLink'; + +const link = new StaticMockLink(checkInQueryMock, true); + +describe('Testing CheckIn Wrapper', () => { + const props = { + eventId: 'event123', + }; + + test('The button to open and close the modal should work properly', async () => { + render( + + + + + + + + + + + + , + ); + + // Open the modal + fireEvent.click(screen.getByLabelText('checkInRegistrants') as Element); + + await waitFor(() => + expect(screen.queryByTestId('modal-title')).toBeInTheDocument(), + ); + + // Close the modal + const closebtn = screen.getByLabelText('Close'); + + fireEvent.click(closebtn as Element); + + await waitFor(() => + expect(screen.queryByTestId('modal-title')).not.toBeInTheDocument(), + ); + }); +}); diff --git a/src/components/CheckIn/CheckInWrapper.tsx b/src/components/CheckIn/CheckInWrapper.tsx new file mode 100644 index 0000000000..9a87a12ed3 --- /dev/null +++ b/src/components/CheckIn/CheckInWrapper.tsx @@ -0,0 +1,41 @@ +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'; + +type PropType = { + eventId: string; +}; + +export const CheckInWrapper = (props: PropType): JSX.Element => { + const [showModal, setShowModal] = useState(false); + + return ( + <> + + {showModal && ( + setShowModal(false)} + eventId={props.eventId} + /> + )} + + ); +}; diff --git a/src/components/CheckIn/TableRow.test.tsx b/src/components/CheckIn/TableRow.test.tsx new file mode 100644 index 0000000000..9a206047d0 --- /dev/null +++ b/src/components/CheckIn/TableRow.test.tsx @@ -0,0 +1,137 @@ +import React from 'react'; +import { fireEvent, render, waitFor } from '@testing-library/react'; +import { TableRow } from './TableRow'; +import { BrowserRouter } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import { I18nextProvider } from 'react-i18next'; +import i18nForTest from 'utils/i18nForTest'; +import { ToastContainer } from 'react-toastify'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { MockedProvider } from '@apollo/react-testing'; +import { checkInMutationSuccess, checkInMutationUnsuccess } from './mocks'; + +describe('Testing Table Row for CheckIn Table', () => { + test('If the user in not checked in, button to check in should be displayed, and the user should be able to check in succesfully', async () => { + const props = { + data: { + id: `123`, + name: `John Doe`, + userId: `user123`, + checkIn: null, + eventId: `event123`, + }, + refetch: jest.fn(), + }; + + const { queryByText } = render( + + + + + + + + + + + + , + ); + + await waitFor(() => expect(queryByText('Check In')).toBeInTheDocument()); + + fireEvent.click(queryByText('Check In') as Element); + + await waitFor(() => + expect(queryByText('Checked in successfully')).toBeInTheDocument(), + ); + }); + + test('If the user in checked in, option to download tag should be shown', async () => { + const props = { + data: { + id: `123`, + name: `John Doe`, + userId: `user123`, + checkIn: { + _id: '123', + time: '12:00:00', + }, + eventId: `event123`, + }, + refetch: jest.fn(), + }; + + const { queryByText } = render( + + + + + + + + + + + + , + ); + + // Stubbing functions required by the @pdfme to show pdfs + global.URL.createObjectURL = jest.fn(); + global.window.open = jest.fn(); + + await waitFor(() => expect(queryByText('Checked In')).toBeInTheDocument()); + await waitFor(() => + expect(queryByText('Download Tag')).toBeInTheDocument(), + ); + + fireEvent.click(queryByText('Download Tag') as Element); + + await waitFor(() => + expect(queryByText('Generating pdf...')).toBeInTheDocument(), + ); + await waitFor(() => { + expect(queryByText('PDF generated successfully!')).toBeInTheDocument(); + }); + }); + + test('Upon failing of check in mutation, the appropiate error message should be shown', async () => { + const props = { + data: { + id: `123`, + name: `John Doe`, + userId: `user123`, + checkIn: null, + eventId: `event123`, + }, + refetch: jest.fn(), + }; + + const { queryByText } = render( + + + + + + + + + + + + , + ); + + await waitFor(() => expect(queryByText('Check In')).toBeInTheDocument()); + + fireEvent.click(queryByText('Check In') as Element); + + await waitFor(() => + expect(queryByText('Error checking in')).toBeInTheDocument(), + ); + await waitFor(() => expect(queryByText('Oops')).toBeInTheDocument()); + }); +}); diff --git a/src/components/CheckIn/TableRow.tsx b/src/components/CheckIn/TableRow.tsx new file mode 100644 index 0000000000..8daa5ed222 --- /dev/null +++ b/src/components/CheckIn/TableRow.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import type { InterfaceTableCheckIn } from './types'; +import Button from '@mui/material/Button'; +import { useMutation } from '@apollo/client'; +import { MARK_CHECKIN } from 'GraphQl/Mutations/mutations'; +import { toast } from 'react-toastify'; +import { generate } from '@pdfme/generator'; +import { tagTemplate } from './tagTemplate'; +import { useTranslation } from 'react-i18next'; + +export const TableRow = ({ + data, + refetch, +}: { + data: InterfaceTableCheckIn; + refetch: () => void; +}): JSX.Element => { + const [checkInMutation] = useMutation(MARK_CHECKIN); + const { t } = useTranslation('translation', { keyPrefix: 'checkIn' }); + + const markCheckIn = (): void => { + // as we do not want to clutter the UI currently with the same (only provide the most basic of operations) + checkInMutation({ + variables: { + userId: data.userId, + eventId: data.eventId, + }, + }) + .then(() => { + toast.success(t('checkedInSuccessfully')); + refetch(); + }) + .catch((err) => { + toast.error(t('errorCheckingIn')); + toast.error(err.message); + }); + }; + + const notify = (): Promise => + toast.promise(generateTag, { + pending: 'Generating pdf...', + success: 'PDF generated successfully!', + error: 'Error generating pdf!', + }); + const generateTag = async (): Promise => { + const inputs = [{ name: data.name }]; + const pdf = await generate({ template: tagTemplate, inputs }); + const blob = new Blob([pdf.buffer], { type: 'application/pdf' }); + window.open(URL.createObjectURL(blob)); + }; + + return ( + <> + {data.checkIn !== null ? ( +
    + + +
    + ) : ( + + )} + + ); +}; diff --git a/src/components/CheckIn/mocks.ts b/src/components/CheckIn/mocks.ts new file mode 100644 index 0000000000..a4e78aa2fc --- /dev/null +++ b/src/components/CheckIn/mocks.ts @@ -0,0 +1,76 @@ +import { EVENT_CHECKINS } from 'GraphQl/Queries/Queries'; +import { MARK_CHECKIN } from 'GraphQl/Mutations/mutations'; +import type { InterfaceAttendeeQueryResponse } from './types'; + +const checkInQueryData: InterfaceAttendeeQueryResponse = { + event: { + _id: 'event123', + attendeesCheckInStatus: [ + { + _id: 'eventAttendee1', + user: { + _id: 'user1', + firstName: 'John', + lastName: 'Doe', + }, + checkIn: null, + }, + { + _id: 'eventAttendee2', + user: { + _id: 'user2', + firstName: 'John2', + lastName: 'Doe2', + }, + checkIn: { + _id: 'checkin1', + time: '08:00:00', + }, + }, + ], + }, +}; + +export const checkInQueryMock = [ + { + request: { + query: EVENT_CHECKINS, + variables: { id: 'event123' }, + }, + result: { + data: checkInQueryData, + }, + }, +]; + +export const checkInMutationSuccess = [ + { + request: { + query: MARK_CHECKIN, + variables: { + userId: 'user123', + eventId: 'event123', + }, + }, + result: { + data: { + checkIn: { + _id: '123', + }, + }, + }, + }, +]; + +export const checkInMutationUnsuccess = [ + { + request: { + query: MARK_CHECKIN, + variables: { + userId: 'user123', + eventId: 'event123', + }, + }, + error: new Error('Oops'), + }, +]; diff --git a/src/components/CheckIn/tagTemplate.ts b/src/components/CheckIn/tagTemplate.ts new file mode 100644 index 0000000000..0af9eeeb15 --- /dev/null +++ b/src/components/CheckIn/tagTemplate.ts @@ -0,0 +1,22 @@ +import { Template } from '@pdfme/generator'; + +export const tagTemplate: Template = { + schemas: [ + { + 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', + }, + }, + ], + 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/CheckIn/types.ts b/src/components/CheckIn/types.ts new file mode 100644 index 0000000000..2fcb2d63cf --- /dev/null +++ b/src/components/CheckIn/types.ts @@ -0,0 +1,44 @@ +export interface InterfaceUser { + _id: string; + firstName: string; + lastName: string; +} + +export interface InterfaceAttendeeCheckIn { + _id: string; + user: InterfaceUser; + checkIn: null | { + _id: string; + time: string; + }; +} + +export interface InterfaceAttendeeQueryResponse { + event: { + _id: string; + attendeesCheckInStatus: InterfaceAttendeeCheckIn[]; + }; +} + +export interface InterfaceModalProp { + show: boolean; + eventId: string; + handleClose: () => void; +} + +export interface InterfaceTableCheckIn { + id: string; + name: string; + userId: string; + checkIn: null | { + _id: string; + time: string; + }; + eventId: string; +} + +export interface InterfaceTableData { + userName: string; + id: string; + checkInData: InterfaceTableCheckIn; +} diff --git a/src/components/CollapsibleDropdown/CollapsibleDropdown.module.css b/src/components/CollapsibleDropdown/CollapsibleDropdown.module.css new file mode 100644 index 0000000000..4337742ecc --- /dev/null +++ b/src/components/CollapsibleDropdown/CollapsibleDropdown.module.css @@ -0,0 +1,14 @@ +.iconWrapper { + width: 36px; +} + +.collapseBtn { + height: 48px; +} + +.iconWrapperSm { + width: 36px; + display: flex; + justify-content: center; + align-items: center; +} diff --git a/src/components/CollapsibleDropdown/CollapsibleDropdown.test.tsx b/src/components/CollapsibleDropdown/CollapsibleDropdown.test.tsx new file mode 100644 index 0000000000..cfb1001e6b --- /dev/null +++ b/src/components/CollapsibleDropdown/CollapsibleDropdown.test.tsx @@ -0,0 +1,102 @@ +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import { BrowserRouter } from 'react-router-dom'; + +import CollapsibleDropdown from './CollapsibleDropdown'; +import type { InterfaceCollapsibleDropdown } from './CollapsibleDropdown'; +import { store } from 'state/store'; +import { Provider } from 'react-redux'; +import { I18nextProvider } from 'react-i18next'; +import i18nForTest from 'utils/i18nForTest'; + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useLocation: () => ({ + pathname: '/orgstore', + state: {}, + key: '', + search: '', + hash: '', + }), +})); + +const props: InterfaceCollapsibleDropdown = { + showDropdown: true, + setShowDropdown: jest.fn(), + target: { + name: 'DropDown Category', + url: undefined, + subTargets: [ + { + name: 'SubCategory 1', + url: '/sub-category-1', + icon: 'fa fa-home', + }, + { + name: 'SubCategory 2', + url: '/sub-category-2', + icon: 'fa fa-home', + }, + ], + }, +}; + +describe('Testing CollapsibleDropdown component', () => { + test('Component should be rendered properly', () => { + render( + + + + + + + , + ); + expect(screen.getByText('DropDown Category')).toBeInTheDocument(); + expect(screen.getByText('SubCategory 1')).toBeInTheDocument(); + expect(screen.getByText('SubCategory 2')).toBeInTheDocument(); + }); + + test('Dropdown should be rendered and functioning correctly', () => { + render( + + + + + + + , + ); + const parentDropdownBtn = screen.getByTestId('collapsible-dropdown'); + const activeDropdownBtn = screen.getByText('SubCategory 1'); + const nonActiveDropdownBtn = screen.getByText('SubCategory 2'); + + // Check if dropdown is rendered with correct classes + activeDropdownBtn.click(); + expect(parentDropdownBtn).toBeInTheDocument(); + expect(parentDropdownBtn).toHaveClass('text-white'); + expect(parentDropdownBtn).toHaveClass('btn-success'); + + // Check if active dropdown is rendered with correct classes + expect(activeDropdownBtn).toBeInTheDocument(); + expect(activeDropdownBtn).toHaveClass('text-white'); + expect(activeDropdownBtn).toHaveClass('btn-success'); + + // Check if inactive dropdown is rendered with correct classes + expect(nonActiveDropdownBtn).toBeInTheDocument(); + expect(nonActiveDropdownBtn).toHaveClass('text-secondary'); + expect(nonActiveDropdownBtn).toHaveClass('btn-light'); + + // Check if dropdown is collapsed after clicking on it + fireEvent.click(parentDropdownBtn); + expect(props.setShowDropdown).toHaveBeenCalledWith(false); + + // Check if dropdown is expanded after clicking on it again + fireEvent.click(parentDropdownBtn); + expect(props.setShowDropdown).toHaveBeenCalledWith(true); + + // Click on non active dropdown button and check if it navigates to the correct url + nonActiveDropdownBtn.click(); + expect(window.location.pathname).toBe('/sub-category-2'); + }); +}); diff --git a/src/components/CollapsibleDropdown/CollapsibleDropdown.tsx b/src/components/CollapsibleDropdown/CollapsibleDropdown.tsx new file mode 100644 index 0000000000..4b85a1911b --- /dev/null +++ b/src/components/CollapsibleDropdown/CollapsibleDropdown.tsx @@ -0,0 +1,96 @@ +import React, { useEffect } from 'react'; +import { Button, Collapse } from 'react-bootstrap'; +import type { TargetsType } from 'state/reducers/routesReducer'; +import styles from './CollapsibleDropdown.module.css'; +import IconComponent from 'components/IconComponent/IconComponent'; +import { NavLink, useLocation, useNavigate } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; + +export interface InterfaceCollapsibleDropdown { + showDropdown: boolean; + target: TargetsType; + setShowDropdown: React.Dispatch>; +} + +const collapsibleDropdown = ({ + target, + showDropdown, + setShowDropdown, +}: InterfaceCollapsibleDropdown): JSX.Element => { + const { t: tCommon } = useTranslation('common'); + const { name, subTargets } = target; + const navigate = useNavigate(); + const location = useLocation(); + useEffect(() => { + if (location.pathname.includes('orgstore')) { + setShowDropdown(true); + } else { + setShowDropdown(false); + } + }, [location.pathname]); + + return ( + <> + + +
    + {subTargets && + subTargets.map(({ name, icon: stringIcon, url }, index) => { + return ( + + {({ isActive }) => ( + + )} + + ); + })} +
    +
    + + ); +}; + +export default collapsibleDropdown; diff --git a/src/components/ContriStats/ContriStats.module.css b/src/components/ContriStats/ContriStats.module.css new file mode 100644 index 0000000000..7d6c83ea8e --- /dev/null +++ b/src/components/ContriStats/ContriStats.module.css @@ -0,0 +1,7 @@ +.fonts { + color: #707070; +} + +.fonts > span { + font-weight: 600; +} diff --git a/src/components/ContriStats/ContriStats.test.tsx b/src/components/ContriStats/ContriStats.test.tsx new file mode 100644 index 0000000000..3164c880c8 --- /dev/null +++ b/src/components/ContriStats/ContriStats.test.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import ContriStats from './ContriStats'; +import { I18nextProvider } from 'react-i18next'; +import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client'; +import type { NormalizedCacheObject } from '@apollo/client'; +import i18nForTest from 'utils/i18nForTest'; +import { BACKEND_URL } from 'Constant/constant'; + +const client: ApolloClient = new ApolloClient({ + cache: new InMemoryCache(), + uri: BACKEND_URL, +}); + +describe('Testing Contribution Stats', () => { + const props = { + key: '123', + id: '234', + recentAmount: '200', + highestAmount: '500', + totalAmount: '1000', + }; + + test('should render props and text elements test for the page component', () => { + render( + + + + + , + ); + expect(screen.getByText('Recent Contribution: $')).toBeInTheDocument(); + expect(screen.getByText('Highest Contribution: $')).toBeInTheDocument(); + expect(screen.getByText('Total Contribution: $')).toBeInTheDocument(); + expect(screen.getByText('200')).toBeInTheDocument(); + expect(screen.getByText('500')).toBeInTheDocument(); + expect(screen.getByText('1000')).toBeInTheDocument(); + }); +}); diff --git a/src/components/ContriStats/ContriStats.tsx b/src/components/ContriStats/ContriStats.tsx new file mode 100644 index 0000000000..7891878335 --- /dev/null +++ b/src/components/ContriStats/ContriStats.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; + +import styles from './ContriStats.module.css'; + +interface InterfaceContriStatsProps { + key: string; + id: string; + recentAmount: string; + highestAmount: string; + totalAmount: string; +} + +function contriStats(props: InterfaceContriStatsProps): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'contriStats', + }); + + return ( + <> +

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

    +

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

    +

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

    + + ); +} +export default contriStats; diff --git a/src/components/CurrentHourIndicator/CurrentHourIndicator.module.css b/src/components/CurrentHourIndicator/CurrentHourIndicator.module.css new file mode 100644 index 0000000000..d2c250035a --- /dev/null +++ b/src/components/CurrentHourIndicator/CurrentHourIndicator.module.css @@ -0,0 +1,19 @@ +.round { + background-color: red; + border-radius: 100%; + width: 15px; + height: 15px; +} +.line { + width: 100%; + height: 1px; + background-color: red; + margin: auto; +} +.container { + position: relative; + display: flex; + flex-direction: row; + top: -8px; + left: -9px; +} diff --git a/src/components/CurrentHourIndicator/CurrentHourIndicator.test.tsx b/src/components/CurrentHourIndicator/CurrentHourIndicator.test.tsx new file mode 100644 index 0000000000..084817dc0d --- /dev/null +++ b/src/components/CurrentHourIndicator/CurrentHourIndicator.test.tsx @@ -0,0 +1,10 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import CurrentHourIndicator from './CurrentHourIndicator'; + +describe('Testing Current Hour Indicator', () => { + test('Component Should be rendered properly', async () => { + const { getByTestId } = render(); + expect(getByTestId('container')).toBeInTheDocument(); + }); +}); diff --git a/src/components/CurrentHourIndicator/CurrentHourIndicator.tsx b/src/components/CurrentHourIndicator/CurrentHourIndicator.tsx new file mode 100644 index 0000000000..9e4a85454a --- /dev/null +++ b/src/components/CurrentHourIndicator/CurrentHourIndicator.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import styles from './CurrentHourIndicator.module.css'; + +const CurrentHourIndicator = (): JSX.Element => { + return ( +
    +
    +
    +
    + ); +}; + +export default CurrentHourIndicator; diff --git a/src/components/DeleteOrg/DeleteOrg.module.css b/src/components/DeleteOrg/DeleteOrg.module.css new file mode 100644 index 0000000000..2b15a2ac0c --- /dev/null +++ b/src/components/DeleteOrg/DeleteOrg.module.css @@ -0,0 +1,25 @@ +.settingsBody { + margin: 2.5rem 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; +} + +.cardHeader .cardTitle { + font-size: 1.2rem; + font-weight: 600; +} + +.cardBody { + min-height: 180px; +} + +.cardBody .textBox { + margin: 0 0 3rem 0; + color: var(--bs-secondary); +} diff --git a/src/components/DeleteOrg/DeleteOrg.test.tsx b/src/components/DeleteOrg/DeleteOrg.test.tsx new file mode 100644 index 0000000000..d9ac99f3ad --- /dev/null +++ b/src/components/DeleteOrg/DeleteOrg.test.tsx @@ -0,0 +1,248 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { render, screen } from '@testing-library/react'; +import 'jest-location-mock'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; + +import { + DELETE_ORGANIZATION_MUTATION, + REMOVE_SAMPLE_ORGANIZATION_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import { act } from 'react-dom/test-utils'; +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18nForTest from 'utils/i18nForTest'; +import DeleteOrg from './DeleteOrg'; +import { ToastContainer, toast } from 'react-toastify'; +import { IS_SAMPLE_ORGANIZATION_QUERY } from 'GraphQl/Queries/Queries'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem } = useLocalStorage(); + +async function wait(ms = 1000): Promise { + await act(async () => { + await new Promise((resolve) => setTimeout(resolve, ms)); + }); +} + +const MOCKS = [ + { + request: { + query: IS_SAMPLE_ORGANIZATION_QUERY, + variables: { + isSampleOrganizationId: '123', + }, + }, + result: { + data: { + isSampleOrganization: true, + }, + }, + }, + { + request: { + query: REMOVE_SAMPLE_ORGANIZATION_MUTATION, + }, + result: { + data: { + removeSampleOrganization: true, + }, + }, + }, + { + request: { + query: DELETE_ORGANIZATION_MUTATION, + variables: { + id: '456', + }, + }, + result: { + data: { + removeOrganization: { + _id: '456', + }, + }, + }, + }, +]; + +const MOCKS_WITH_ERROR = [ + { + request: { + query: IS_SAMPLE_ORGANIZATION_QUERY, + variables: { + isSampleOrganizationId: '123', + }, + }, + result: { + data: { + isSampleOrganization: true, + }, + }, + }, + { + request: { + query: DELETE_ORGANIZATION_MUTATION, + variables: { + id: '456', + }, + }, + error: new Error('Failed to delete organization'), + }, + { + request: { + query: REMOVE_SAMPLE_ORGANIZATION_MUTATION, + }, + error: new Error('Failed to delete sample organization'), + }, +]; +const mockNavgatePush = jest.fn(); +let mockURL = '123'; +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: mockURL }), + useNavigate: () => mockNavgatePush, +})); + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(MOCKS_WITH_ERROR, true); + +afterEach(() => { + localStorage.clear(); +}); + +describe('Delete Organization Component', () => { + test('should be able to Toggle Delete Organization Modal', async () => { + mockURL = '456'; + setItem('SuperAdmin', true); + render( + + + + + + + + + + , + ); + await wait(); + screen.getByTestId(/openDeleteModalBtn/i).click(); + expect(screen.getByTestId(/orgDeleteModal/i)).toBeInTheDocument(); + screen.getByTestId(/closeDelOrgModalBtn/i).click(); + await act(async () => { + expect(screen.queryByTestId(/orgDeleteModal/i)).not.toHaveFocus(); + }); + }); + + test('should be able to Toggle Delete Organization Modal When Organization is Sample Organization', async () => { + mockURL = '123'; + setItem('SuperAdmin', true); + render( + + + + + + + + + + , + ); + await wait(); + screen.getByTestId(/openDeleteModalBtn/i).click(); + expect(screen.getByTestId(/orgDeleteModal/i)).toBeInTheDocument(); + screen.getByTestId(/closeDelOrgModalBtn/i).click(); + await act(async () => { + expect(screen.queryByTestId(/orgDeleteModal/i)).not.toHaveFocus(); + }); + }); + + test('Delete organization functionality should work properly', async () => { + mockURL = '456'; + setItem('SuperAdmin', true); + render( + + + + + + + + + , + ); + await wait(); + screen.getByTestId(/openDeleteModalBtn/i).click(); + screen.getByTestId(/deleteOrganizationBtn/i).click(); + }); + + test('Delete organization functionality should work properly for sample org', async () => { + mockURL = '123'; + setItem('SuperAdmin', true); + render( + + + + + + + + + , + ); + await wait(); + screen.getByTestId(/openDeleteModalBtn/i).click(); + screen.getByTestId(/deleteOrganizationBtn/i).click(); + await wait(2000); + expect(mockNavgatePush).toHaveBeenCalledWith('/orglist'); + }); + + test('Error handling for IS_SAMPLE_ORGANIZATION_QUERY mock', async () => { + mockURL = '123'; + setItem('SuperAdmin', true); + jest.spyOn(toast, 'error'); + render( + + + + + + + + + , + ); + await wait(); + screen.getByTestId(/openDeleteModalBtn/i).click(); + screen.getByTestId(/deleteOrganizationBtn/i).click(); + await wait(); + expect(toast.error).toHaveBeenCalledWith( + 'Failed to delete sample organization', + ); + }); + + test('Error handling for DELETE_ORGANIZATION_MUTATION mock', async () => { + mockURL = '456'; + setItem('SuperAdmin', true); + render( + + + + + + + + + , + ); + await wait(); + screen.getByTestId(/openDeleteModalBtn/i).click(); + screen.getByTestId(/deleteOrganizationBtn/i).click(); + await wait(); + }); +}); diff --git a/src/components/DeleteOrg/DeleteOrg.tsx b/src/components/DeleteOrg/DeleteOrg.tsx new file mode 100644 index 0000000000..ab2772785f --- /dev/null +++ b/src/components/DeleteOrg/DeleteOrg.tsx @@ -0,0 +1,120 @@ +import React, { useState } from 'react'; +import { Button, Card, Modal } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; +import { useMutation, useQuery } from '@apollo/client'; +import { errorHandler } from 'utils/errorHandler'; +import { toast } from 'react-toastify'; +import { + DELETE_ORGANIZATION_MUTATION, + REMOVE_SAMPLE_ORGANIZATION_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import { IS_SAMPLE_ORGANIZATION_QUERY } from 'GraphQl/Queries/Queries'; +import styles from './DeleteOrg.module.css'; +import { useNavigate, useParams } from 'react-router-dom'; +import useLocalStorage from 'utils/useLocalstorage'; + +function deleteOrg(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'deleteOrg', + }); + const { t: tCommon } = useTranslation('common'); + const { orgId: currentUrl } = useParams(); + const navigate = useNavigate(); + const [showDeleteModal, setShowDeleteModal] = useState(false); + const { getItem } = useLocalStorage(); + const canDelete = getItem('SuperAdmin'); + const toggleDeleteModal = (): void => setShowDeleteModal(!showDeleteModal); + + const [del] = useMutation(DELETE_ORGANIZATION_MUTATION); + const [removeSampleOrganization] = useMutation( + REMOVE_SAMPLE_ORGANIZATION_MUTATION, + ); + + const { data } = useQuery(IS_SAMPLE_ORGANIZATION_QUERY, { + variables: { + isSampleOrganizationId: currentUrl, + }, + }); + + const deleteOrg = async (): Promise => { + if (data && data.isSampleOrganization) { + removeSampleOrganization() + .then(() => { + toast.success(t('successfullyDeletedSampleOrganization')); + setTimeout(() => { + navigate('/orglist'); + }, 1000); + }) + .catch((error) => { + toast.error(error.message); + }); + } else { + try { + await del({ + variables: { + id: currentUrl, + }, + }); + navigate('/orglist'); + } catch (error) { + errorHandler(t, error); + } + } + }; + + return ( + <> + {canDelete && ( + +
    +
    {t('deleteOrganization')}
    +
    + +
    {t('longDelOrgMsg')}
    + +
    +
    + )} + {/* Delete Organization Modal */} + {canDelete && ( + + +
    {t('deleteOrganization')}
    +
    + {t('deleteMsg')} + + + + +
    + )} + + ); +} + +export default deleteOrg; diff --git a/src/components/DynamicDropDown/DynamicDropDown.module.css b/src/components/DynamicDropDown/DynamicDropDown.module.css new file mode 100644 index 0000000000..0edf85b621 --- /dev/null +++ b/src/components/DynamicDropDown/DynamicDropDown.module.css @@ -0,0 +1,12 @@ +.dropwdownToggle { + background-color: #f1f3f6; + color: black; + border: none; + padding: 0.5rem; + text-align: left; + display: flex; + align-items: center; + justify-content: space-between; + min-width: 8rem; + outline: 1px solid var(--bs-gray-400); +} diff --git a/src/components/DynamicDropDown/DynamicDropDown.test.tsx b/src/components/DynamicDropDown/DynamicDropDown.test.tsx new file mode 100644 index 0000000000..c77ac5aebf --- /dev/null +++ b/src/components/DynamicDropDown/DynamicDropDown.test.tsx @@ -0,0 +1,64 @@ +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 new file mode 100644 index 0000000000..170b6be29b --- /dev/null +++ b/src/components/DynamicDropDown/DynamicDropDown.tsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { Dropdown } from 'react-bootstrap'; +import styles from './DynamicDropDown.module.css'; + +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 +} + +const DynamicDropDown = (props: InterfaceChangeDropDownProps): JSX.Element => { + const handleFieldChange = (value: string): void => { + props.setFormState({ ...props.formState, [props.fieldName]: value }); + }; + + const getLabel = (value: string): string => { + const selectedOption = props.fieldOptions.find( + (option) => option.value === value, + ); + return selectedOption ? selectedOption.label : `None`; + }; + + return ( + + + {getLabel(props.formState[props.fieldName])} + + + {props.fieldOptions.map((option, index: number) => ( + handleFieldChange(option.value)} + data-testid={`change-${props.fieldName.toLowerCase()}-btn-${option.value}`} + > + {option.label} + + ))} + + + ); +}; + +export default DynamicDropDown; diff --git a/src/components/EditCustomFieldDropDown/EditCustomFieldDropDown.test.tsx b/src/components/EditCustomFieldDropDown/EditCustomFieldDropDown.test.tsx new file mode 100644 index 0000000000..2e3c52ad38 --- /dev/null +++ b/src/components/EditCustomFieldDropDown/EditCustomFieldDropDown.test.tsx @@ -0,0 +1,64 @@ +import type { Dispatch, SetStateAction } from 'react'; +import React from 'react'; +import { act, render } from '@testing-library/react'; +import { BrowserRouter } from 'react-router-dom'; +import EditOrgCustomFieldDropDown from './EditCustomFieldDropDown'; +import type { InterfaceCustomFieldData } from 'components/OrgProfileFieldSettings/OrgProfileFieldSettings'; +import userEvent from '@testing-library/user-event'; +import availableFieldTypes from 'utils/fieldTypes'; +import { I18nextProvider } from 'react-i18next'; +import i18nForTest from 'utils/i18nForTest'; + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +describe('Testing Custom Field Dropdown', () => { + test('Component Should be rendered properly', async () => { + const customFieldData = { + type: 'Number', + name: 'Age', + }; + + const setCustomFieldData: Dispatch< + SetStateAction + > = (val) => { + { + val; + } + }; + const props = { + customFieldData: customFieldData as InterfaceCustomFieldData, + setCustomFieldData: setCustomFieldData, + parentContainerStyle: 'parentContainerStyle', + btnStyle: 'btnStyle', + btnTextStyle: 'btnTextStyle', + }; + + const { getByTestId, getByText } = render( + + + + + , + ); + + expect(getByText('Number')).toBeInTheDocument(); + + act(() => { + userEvent.click(getByTestId('toggleBtn')); + }); + + await wait(); + + availableFieldTypes.forEach(async (_, index) => { + act(() => { + userEvent.click(getByTestId(`dropdown-btn-${index}`)); + }); + }); + }); +}); diff --git a/src/components/EditCustomFieldDropDown/EditCustomFieldDropDown.tsx b/src/components/EditCustomFieldDropDown/EditCustomFieldDropDown.tsx new file mode 100644 index 0000000000..7a81e78e27 --- /dev/null +++ b/src/components/EditCustomFieldDropDown/EditCustomFieldDropDown.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import type { SetStateAction, Dispatch } from 'react'; +import { Dropdown } from 'react-bootstrap'; +import availableFieldTypes from 'utils/fieldTypes'; +import type { InterfaceCustomFieldData } from 'components/OrgProfileFieldSettings/OrgProfileFieldSettings'; +import { useTranslation } from 'react-i18next'; + +interface InterfaceEditCustomFieldDropDownProps { + customFieldData: InterfaceCustomFieldData; + setCustomFieldData: Dispatch>; + parentContainerStyle?: string; + btnStyle?: string; + btnTextStyle?: string; +} + +const EditOrgCustomFieldDropDown = ({ + customFieldData, + setCustomFieldData, + parentContainerStyle, + btnStyle, +}: InterfaceEditCustomFieldDropDownProps): JSX.Element => { + const { t } = useTranslation('translation', { + keyPrefix: 'orgProfileField', + }); + const { t: tCommon } = useTranslation('common'); + + return ( + + + {customFieldData.type ? t(customFieldData.type) : tCommon('none')} + + + {availableFieldTypes.map((customFieldType, index: number) => ( + { + setCustomFieldData({ + ...customFieldData, + type: customFieldType, + }); + }} + disabled={customFieldData.type === customFieldType} + > + {t(customFieldType)} + + ))} + + + ); +}; + +export default EditOrgCustomFieldDropDown; diff --git a/src/components/EventCalendar/EventCalendar.module.css b/src/components/EventCalendar/EventCalendar.module.css new file mode 100644 index 0000000000..67ecd2dec6 --- /dev/null +++ b/src/components/EventCalendar/EventCalendar.module.css @@ -0,0 +1,342 @@ +.calendar { + font-family: sans-serif; + font-size: 1.2rem; + margin-bottom: 20px; + background: rgb(255, 255, 255); + 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; + font-weight: 800; + font-size: 55px; + display: flex; + gap: 23px; + flex-direction: row; +} +.calendar__header_month div { + font-weight: 400; + color: black; + font-family: Outfit; +} +.space { + flex: 1; + display: flex; + align-items: center; + justify-content: space-around; +} +.button { + border-radius: 100px; + color: #707070; + background-color: rgba(194, 247, 182, 0); + font-weight: bold; + border: 0px; + font-size: 20px; +} + +.calendar__weekdays { + display: grid; + grid-template-columns: repeat(7, 1fr); + background-color: black; + font-family: Outfit; + height: 60px; +} +.calendar__scroll { + height: 80vh; + padding: 10px; +} +.weekday { + display: flex; + justify-content: center; + align-items: center; + 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; + align-items: flex-end; + border-right: 1px solid #8d8d8d55; + width: 40px; +} +.calendar_hour_text { + top: -10px; + left: -5px; + position: relative; + color: #707070; + font-size: 12px; +} +.calendar_timezone_text { + top: -10px; + left: -11px; + position: relative; + color: #707070; + font-size: 9px; +} +.calendar_hour_block { + display: flex; + flex-direction: row; + border-bottom: 1px solid #8d8d8d55; + position: relative; + 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; + padding-right: 0.3rem; + border-radius: 10px; + margin: 5px; + background-color: white; + border: 1px solid #8d8d8d55; + color: #4b4b4b; + font-weight: 600; + 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; + color: #ffffff; + font-size: 18px; + padding: 10px 20px 10px 20px; + text-decoration: none; + margin-left: 20px; + border: none; +} +.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; +} + +.dropdown { + border-color: #31bb6b; + background-color: white; + color: #31bb6b; + box-shadow: 0px 2px 1px rgba(49, 187, 107, 0.5); /* Added blur effect */ +} + +.btnsContainer .input { + flex: 1; + position: relative; +} + +.btnsContainer input { + outline: 1px solid var(--bs-gray-400); +} + +.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; +} +.btn__more { + border: 0px; + font-size: 14px; + background-color: initial; + color: #262727; + font-weight: 600; + transition: all 200ms; + position: relative; + display: block; + margin: 2px; +} +.btn__more:hover { + color: #454645; +} + +.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; +} +.expand_list_container { + width: 200px; + max-height: 250px; + z-index: 10; + position: absolute; + left: auto; + right: auto; + overflow: auto; + padding: 10px 4px 0px 4px; + background-color: rgb(241, 241, 241); + border: 1px solid rgb(201, 201, 201); + border-radius: 5px; + margin: 5px; +} +.flex_grow { + flex-grow: 1; +} + +@media only screen and (max-width: 700px) { + .event_list { + display: none; + } + .expand_list_container { + width: 150px; + padding: 4px 4px 0px 4px; + } + .day { + height: 5rem; + } +} + +@media only screen and (max-width: 500px) { + .btn__more { + font-size: 12px; + } +} + +.calendar__infocards { + display: flex; + flex-direction: row; + justify-content: space-between; + gap: 10px; + margin-top: 35px; +} +.card__holidays { + background-color: rgba(246, 242, 229, 1); + display: flex; + flex-direction: column; + width: 50%; + font-family: Outfit; + border-radius: 20px; + padding: 30px; + text-overflow: ellipsis; + 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; + flex-direction: column; + width: 50%; + font-family: Outfit; + 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; + background: rgba(0, 0, 0, 0.15); + border-radius: 10px; +} + +.userEvents__color { + height: 15px; + width: 40px; + background: rgba(146, 200, 141, 0.5); + border-radius: 10px; +} diff --git a/src/components/EventCalendar/EventCalendar.test.tsx b/src/components/EventCalendar/EventCalendar.test.tsx new file mode 100644 index 0000000000..caca516763 --- /dev/null +++ b/src/components/EventCalendar/EventCalendar.test.tsx @@ -0,0 +1,413 @@ +import Calendar from './EventCalendar'; +import { render, screen, fireEvent, act } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider } from 'react-i18next'; +import React from 'react'; +import { ViewType } from 'screens/OrganizationEvents/OrganizationEvents'; + +import { + DELETE_EVENT_MUTATION, + UPDATE_EVENT_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import i18nForTest from 'utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { weekdays, months } from './constants'; +import { BrowserRouter as Router } from 'react-router-dom'; + +const eventData = [ + { + _id: '1', + title: 'Event 1', + description: 'This is event 1', + startDate: '2022-05-01', + endDate: '2022-05-01', + location: 'New York', + startTime: '10:00', + endTime: '12:00', + allDay: false, + recurring: false, + recurrenceRule: null, + isRecurringEventException: false, + isPublic: true, + isRegisterable: true, + viewType: ViewType.DAY, + }, + { + _id: '2', + title: 'Event 2', + description: 'This is event 2', + startDate: '2022-05-03', + endDate: '2022-05-03', + location: 'Los Angeles', + startTime: '14:00', + endTime: '16:00', + allDay: false, + recurring: false, + recurrenceRule: null, + isRecurringEventException: false, + isPublic: true, + isRegisterable: true, + }, +]; + +const MOCKS = [ + { + request: { + query: DELETE_EVENT_MUTATION, + variable: { id: '123' }, + }, + result: { + data: { + removeEvent: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: UPDATE_EVENT_MUTATION, + variable: { + id: '123', + title: 'Updated title', + description: 'This is a new update', + isPublic: true, + recurring: false, + isRegisterable: true, + allDay: false, + location: 'New Delhi', + startTime: '02:00', + endTime: '07:00', + }, + }, + result: { + data: { + updateEvent: { + _id: '1', + }, + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); + +async function wait(ms = 200): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +describe('Calendar', () => { + it('renders weekdays', () => { + render(); + + weekdays.forEach((weekday) => { + expect(screen.getByText(weekday)).toBeInTheDocument(); + }); + }); + it('should initialize currentMonth and currentYear with the current date', () => { + const today = new Date(); + const { getByTestId } = render(); + + const currentMonth = getByTestId('current-date'); + const currentYear = getByTestId('current-date'); + + expect(currentMonth).toHaveTextContent( + today.toLocaleString('default', { month: 'long' }), + ); + expect(currentYear).toHaveTextContent(today.getFullYear().toString()); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should render the current month and year', () => { + const { getByTestId } = render(); + + // Find the element by its data-testid attribute + const currentDateElement = getByTestId('current-date'); + + // Assert that the text content of the element matches the current month and year + const currentMonth = new Date().toLocaleString('default', { + month: 'long', + }); + const currentYear = new Date().getFullYear(); + const expectedText = ` ${currentYear} ${currentMonth}`; + expect(currentDateElement.textContent).toContain(expectedText); + }); + + it('Should show prev and next month on clicking < & > buttons', () => { + //testing previous month button + render( + + + + + , + ); + const prevButton = screen.getByTestId('prevmonthordate'); + fireEvent.click(prevButton); + //testing next month button + const nextButton = screen.getByTestId('nextmonthordate'); + fireEvent.click(nextButton); + //Testing year change + for (let index = 0; index < 13; index++) { + fireEvent.click(nextButton); + } + for (let index = 0; index < 13; index++) { + fireEvent.click(prevButton); + } + }); + it('Should show prev and next year on clicking < & > buttons when in year view', async () => { + //testing previous month button + render( + + + + + , + ); + await wait(); + const prevButtons = screen.getAllByTestId('prevYear'); + prevButtons.forEach((button) => { + fireEvent.click(button); + }); + await wait(); + //testing next year button + const nextButton = screen.getAllByTestId('prevYear'); + nextButton.forEach((button) => { + fireEvent.click(button); + }); + }); + it('Should show prev and next date on clicking < & > buttons in the day view', async () => { + render( + + + + + + + , + ); + //testing previous date button + const prevButton = screen.getByTestId('prevmonthordate'); + fireEvent.click(prevButton); + //testing next date button + const nextButton = screen.getByTestId('nextmonthordate'); + fireEvent.click(nextButton); + //Testing year change and month change + for (let index = 0; index < 366; index++) { + fireEvent.click(prevButton); + } + for (let index = 0; index < 732; index++) { + fireEvent.click(nextButton); + } + }); + it('Should render eventlistcard of current day event', () => { + const currentDayEventMock = [ + { + _id: '0', + title: 'demo', + description: 'agrsg', + startDate: new Date().toISOString().split('T')[0], + endDate: new Date().toISOString().split('T')[0], + location: 'delhi', + startTime: '10:00', + endTime: '12:00', + allDay: false, + recurring: false, + recurrenceRule: null, + isRecurringEventException: false, + isPublic: true, + isRegisterable: true, + }, + ]; + render( + + + + + + + , + , + ); + }); + it('Test for superadmin case', () => { + render( + + + + + + + , + , + ); + }); + it('Today Cell is having correct styles', () => { + render( + + + + + + + , + , + ); + // const todayDate = new Date().getDate(); + // const todayElement = screen.getByText(todayDate.toString()); + // expect(todayElement).toHaveClass(styles.day__today); + }); + it('Today button should show today cell', () => { + render( + + + + + + + , + , + ); + //Changing the month + const prevButton = screen.getByTestId('prevmonthordate'); + fireEvent.click(prevButton); + + // Clicking today button + const todayButton = screen.getByTestId('today'); + fireEvent.click(todayButton); + // const todayCell = screen.getByText(new Date().getDate().toString()); + // expect(todayCell).toHaveClass(styles.day__today); + }); + it('Should handle window resize in day view', async () => { + 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], + location: 'Los Angeles', + startTime: null, + endTime: null, + allDay: true, + recurring: false, + recurrenceRule: null, + isRecurringEventException: false, + isPublic: true, + isRegisterable: true, + }, + { + _id: '2', + title: 'Event 2', + description: 'This is event 2', + startDate: new Date().toISOString().split('T')[0], + endDate: new Date().toISOString().split('T')[0], + location: 'Los Angeles', + startTime: null, + endTime: null, + allDay: true, + recurring: false, + recurrenceRule: null, + isRecurringEventException: false, + isPublic: true, + isRegisterable: true, + }, + { + _id: '3', + title: 'Event 3', + description: 'This is event 3', + startDate: new Date().toISOString().split('T')[0], + endDate: new Date().toISOString().split('T')[0], + location: 'Los Angeles', + startTime: '14:00', + endTime: '16:00', + allDay: false, + recurring: false, + recurrenceRule: null, + isRecurringEventException: false, + isPublic: true, + isRegisterable: true, + }, + { + _id: '4', + title: 'Event 4', + description: 'This is event 4', + startDate: new Date().toISOString().split('T')[0], + endDate: new Date().toISOString().split('T')[0], + location: 'Los Angeles', + startTime: '14:00', + endTime: '16:00', + allDay: false, + recurring: false, + recurrenceRule: null, + isRecurringEventException: false, + isPublic: true, + isRegisterable: true, + }, + { + _id: '5', + title: 'Event 5', + description: 'This is event 5', + startDate: new Date().toISOString().split('T')[0], + endDate: new Date().toISOString().split('T')[0], + location: 'Los Angeles', + startTime: '17:00', + endTime: '19:00', + allDay: false, + recurring: false, + recurrenceRule: null, + isRecurringEventException: false, + isPublic: true, + isRegisterable: true, + }, + ]; + render( + + + + + + + , + , + ); + await act(async () => { + window.innerWidth = 500; + window.dispatchEvent(new Event('resize')); + }); + }); + test('Handles window resize', () => { + render( + + + + + + + , + , + ); + + act(() => { + window.dispatchEvent(new Event('resize')); + }); + }); + it('renders year view', async () => { + render(); + + await wait(); + months.forEach((month) => { + const elements = screen.getAllByText(month); + elements.forEach((element) => { + expect(element).toBeInTheDocument(); + }); + }); + }); +}); diff --git a/src/components/EventCalendar/EventCalendar.tsx b/src/components/EventCalendar/EventCalendar.tsx new file mode 100644 index 0000000000..566e66d62a --- /dev/null +++ b/src/components/EventCalendar/EventCalendar.tsx @@ -0,0 +1,643 @@ +import EventListCard from 'components/EventListCard/EventListCard'; +import dayjs from 'dayjs'; +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 type { InterfaceRecurrenceRule } from 'utils/recurrenceUtils'; +import YearlyEventCalender from './YearlyEventCalender'; + +interface InterfaceEventListCardProps { + userRole?: string; + key?: string; + _id: string; + location: string; + title: string; + description: string; + startDate: string; + endDate: string; + startTime: string | null; + endTime: string | null; + allDay: boolean; + recurring: boolean; + recurrenceRule: InterfaceRecurrenceRule | null; + isRecurringEventException: boolean; + isPublic: boolean; + isRegisterable: boolean; + attendees?: { + _id: string; + }[]; + creator?: { + firstName: string; + lastName: string; + _id: string; + }; +} + +interface InterfaceCalendarProps { + eventData: InterfaceEventListCardProps[]; + refetchEvents?: () => void; + orgData?: InterfaceIOrgList; + userRole?: string; + userId?: string; + viewType?: ViewType; +} + +enum Role { + USER = 'USER', + SUPERADMIN = 'SUPERADMIN', + ADMIN = 'ADMIN', +} + +interface InterfaceIOrgList { + admins: { _id: string }[]; +} +const Calendar: React.FC = ({ + eventData, + refetchEvents, + orgData, + userRole, + userId, + viewType, +}) => { + const [selectedDate] = useState(null); + const today = new Date(); + const [currentDate, setCurrentDate] = useState(today.getDate()); + const [currentMonth, setCurrentMonth] = useState(today.getMonth()); + const [currentYear, setCurrentYear] = useState(today.getFullYear()); + const [events, setEvents] = useState( + null, + ); + const [expanded, setExpanded] = useState(-1); + const [windowWidth, setWindowWidth] = useState(window.screen.width); + + useEffect(() => { + function handleResize(): void { + setWindowWidth(window.screen.width); + } + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + }, []); + + const filterData = ( + eventData: InterfaceEventListCardProps[], + orgData?: InterfaceIOrgList, + userRole?: string, + userId?: string, + ): InterfaceEventListCardProps[] => { + 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); + if (!event.isPublic) { + const filteredOrg: boolean | undefined = orgData?.admins?.some( + (data) => data._id === userId, + ); + + if (filteredOrg) { + data.push(event); + } + } + }); + } else { + eventData?.forEach((event) => { + if (event.isPublic) data.push(event); + const userAttending = event.attendees?.some( + (data) => data._id === userId, + ); + if (userAttending) { + data.push(event); + } + }); + } + return data; + }; + + useEffect(() => { + const data = filterData(eventData, orgData, userRole, userId); + setEvents(data); + }, [eventData, orgData, userRole, userId]); + + const handlePrevMonth = (): void => { + /*istanbul ignore next*/ + if (currentMonth === 0) { + setCurrentMonth(11); + setCurrentYear(currentYear - 1); + } else { + setCurrentMonth(currentMonth - 1); + } + }; + + const handleNextMonth = (): void => { + /*istanbul ignore next*/ + if (currentMonth === 11) { + setCurrentMonth(0); + setCurrentYear(currentYear + 1); + } else { + setCurrentMonth(currentMonth + 1); + } + }; + + const handlePrevDate = (): void => { + /*istanbul ignore next*/ + if (currentDate > 1) { + setCurrentDate(currentDate - 1); + } else { + if (currentMonth > 0) { + const lastDayOfPrevMonth = new Date( + currentYear, + currentMonth, + 0, + ).getDate(); + setCurrentDate(lastDayOfPrevMonth); + setCurrentMonth(currentMonth - 1); + } else { + setCurrentDate(31); + setCurrentMonth(11); + setCurrentYear(currentYear - 1); + } + } + }; + /*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 { + if (currentMonth < 12) { + setCurrentDate(1); + setCurrentMonth(currentMonth + 1); + } else { + setCurrentDate(1); + setCurrentMonth(1); + setCurrentYear(currentYear + 1); + } + } + }; + + const handleTodayButton = (): void => { + /*istanbul ignore next*/ + setCurrentYear(today.getFullYear()); + setCurrentMonth(today.getMonth()); + setCurrentDate(today.getDate()); + }; + + const timezoneString = `UTC${ + new Date().getTimezoneOffset() > 0 ? '-' : '+' + }${String(Math.floor(Math.abs(new Date().getTimezoneOffset()) / 60)).padStart( + 2, + '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) { + setExpanded(-1); + } else { + setExpanded(index); + } + }; + + /*istanbul ignore next*/ + const allDayEventsList: JSX.Element[] = + events + ?.filter((datas) => { + /*istanbul ignore next*/ + const currDate = new Date(currentYear, currentMonth, currentDate); + if ( + datas.startTime == undefined && + 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 ( + + ); + }) || []; + + return ( + <> +
    +
    +

    {timezoneString}

    +
    +
    +
    0 + ? styles.event_list_parent_current + : styles.event_list_parent + } + > +
    +
    + {expanded === -100 + ? allDayEventsList + : allDayEventsList?.slice(0, 1)} +
    + {(allDayEventsList?.length > 2 || + (windowWidth <= 700 && allDayEventsList?.length > 0)) && ( + + )} +
    +
    +
    + {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}`}

    +
    +
    +
    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)) && ( + + )} +
    +
    +
    + ); + })} + + ); + }; + + const renderDays = (): JSX.Element[] => { + const monthStart = new Date(currentYear, currentMonth, 1); + const monthEnd = new Date(currentYear, currentMonth + 1, 0); + const startDate = new Date( + monthStart.getFullYear(), + monthStart.getMonth(), + monthStart.getDate() - monthStart.getDay(), + ); + const endDate = new Date( + monthEnd.getFullYear(), + monthEnd.getMonth(), + monthEnd.getDate() + (6 - monthEnd.getDay()), + ); + const days = []; + let currentDate = startDate; + while (currentDate <= endDate) { + days.push(currentDate); + currentDate = new Date( + currentDate.getFullYear(), + currentDate.getMonth(), + currentDate.getDate() + 1, + ); + } + + 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 + ? styles.day__today + : '', + date.getMonth() !== currentMonth ? styles.day__outside : '', //Styling for days outside the current month + 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) => { + if (datas.startDate == dayjs(date).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 ( + + ); + }) || []; + + const holidayList: JSX.Element[] = holidays + .filter((holiday) => { + if (holiday.date == dayjs(date).format('MM-DD')) return holiday; + }) + .map((holiday) => { + return ; + }); + return ( +
    0 && styles.day__events) + } + data-testid="day" + > + {date.getDate()} + {date.getMonth() !== currentMonth ? null : ( +
    +
    +
    {holidayList}
    + { + /*istanbul ignore next*/ + expanded === index + ? allEventsList + : holidayList?.length > 0 + ? /*istanbul ignore next*/ + allEventsList?.slice(0, 1) + : allEventsList?.slice(0, 2) + } +
    + {(allEventsList?.length > 2 || + (windowWidth <= 700 && allEventsList?.length > 0)) && ( + /*istanbul ignore next*/ + + )} +
    + )} +
    + ); + }); + }; + + return ( +
    + {viewType != ViewType.YEAR && ( +
    + + +
    + {viewType == ViewType.DAY ? `${currentDate}` : ``} {currentYear}{' '} +
    {months[currentMonth]}
    +
    + +
    + +
    +
    + )} +
    + {viewType == ViewType.MONTH ? ( +
    +
    + {weekdays.map((weekday, index) => ( +
    + {weekday} +
    + ))} +
    +
    {renderDays()}
    +
    + ) : ( + // +
    + {viewType == ViewType.YEAR ? ( + + ) : ( +
    {renderHours()}
    + )} +
    + )} +
    +
    + {viewType == ViewType.YEAR ? ( + + ) : ( +
    {renderHours()}
    + )} +
    +
    + ); +}; + +export default Calendar; diff --git a/src/components/EventCalendar/EventHeader.test.tsx b/src/components/EventCalendar/EventHeader.test.tsx new file mode 100644 index 0000000000..215182af9c --- /dev/null +++ b/src/components/EventCalendar/EventHeader.test.tsx @@ -0,0 +1,100 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import EventHeader from './EventHeader'; +import { ViewType } from '../../screens/OrganizationEvents/OrganizationEvents'; +import { I18nextProvider } from 'react-i18next'; +import i18nForTest from 'utils/i18nForTest'; +import { act } from 'react-dom/test-utils'; // Import act for async testing + +describe('EventHeader Component', () => { + const viewType = ViewType.MONTH; + const handleChangeView = jest.fn(); + const showInviteModal = jest.fn(); + + it('renders correctly', () => { + const { getByTestId } = render( + + + , + ); + + expect(getByTestId('searchEvent')).toBeInTheDocument(); + expect(getByTestId('createEventModalBtn')).toBeInTheDocument(); + }); + + it('calls handleChangeView with selected view type', async () => { + // Add async keyword + const { getByTestId } = render( + + + , + ); + + fireEvent.click(getByTestId('selectViewType')); + + await act(async () => { + fireEvent.click(getByTestId('selectDay')); + }); + + // Expect handleChangeView to be called with the new view type + expect(handleChangeView).toHaveBeenCalledTimes(1); + }); + it('calls handleChangeView with selected event type', async () => { + const { getByTestId } = render( + + + , + ); + + fireEvent.click(getByTestId('eventType')); + + await act(async () => { + fireEvent.click(getByTestId('events')); + }); + + expect(handleChangeView).toHaveBeenCalledTimes(1); + }); + + it('calls showInviteModal when create event button is clicked', () => { + const { getByTestId } = render( + + + , + ); + + fireEvent.click(getByTestId('createEventModalBtn')); + expect(showInviteModal).toHaveBeenCalled(); + }); + it('updates the input value when changed', () => { + const { getByTestId } = render( + + + , + ); + + const input = getByTestId('searchEvent') as HTMLInputElement; + fireEvent.change(input, { target: { value: 'test event' } }); + + expect(input.value).toBe('test event'); + }); +}); diff --git a/src/components/EventCalendar/EventHeader.tsx b/src/components/EventCalendar/EventHeader.tsx new file mode 100644 index 0000000000..a4bc59596c --- /dev/null +++ b/src/components/EventCalendar/EventHeader.tsx @@ -0,0 +1,110 @@ +import React, { useState } from 'react'; +import { Button, Dropdown, Form } from 'react-bootstrap'; +import { Search } from '@mui/icons-material'; +import styles from './EventCalendar.module.css'; +import { ViewType } from '../../screens/OrganizationEvents/OrganizationEvents'; +import { useTranslation } from 'react-i18next'; + +interface InterfaceEventHeaderProps { + viewType: ViewType; + handleChangeView: (item: string | null) => void; + showInviteModal: () => void; +} + +function eventHeader({ + viewType, + handleChangeView, + showInviteModal, +}: InterfaceEventHeaderProps): JSX.Element { + const [eventName, setEventName] = useState(''); + const { t } = useTranslation('translation', { + keyPrefix: 'organizationEvents', + }); + + return ( +
    +
    +
    + setEventName(e.target.value)} + /> + +
    +
    +
    +
    + + + {viewType} + + + + {ViewType.MONTH} + + + {ViewType.DAY} + + + {ViewType.YEAR} + + + +
    +
    + + + {t('eventType')} + + + + Events + + + Workshops + + + +
    + +
    +
    +
    + ); +} + +export default eventHeader; diff --git a/src/components/EventCalendar/YearlyEventCalender.module.css b/src/components/EventCalendar/YearlyEventCalender.module.css new file mode 100644 index 0000000000..723cb20e22 --- /dev/null +++ b/src/components/EventCalendar/YearlyEventCalender.module.css @@ -0,0 +1,354 @@ +.calendar { + font-family: sans-serif; + font-size: 1.2rem; + margin-bottom: 20px; +} +.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; + font-weight: bold; +} +.space { + flex: 1; + display: flex; + align-items: center; + justify-content: space-around; +} +.button { + color: #707070; + background-color: rgba(0, 0, 0, 0); + font-weight: bold; + border: 0px; +} +.calendar__weekdays { + display: grid; + grid-template-columns: repeat(7, 1fr); + background-color: #707070; + height: 60px; +} +.calendar__scroll { + height: 80vh; + padding: 10px; +} +.weekday { + display: flex; + justify-content: center; + align-items: center; + color: #fff; + background-color: #31bb6b; + 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; + align-items: flex-end; + border-right: 1px solid #8d8d8d55; + width: 40px; +} +.calendar_hour_text { + top: -10px; + left: -5px; + position: relative; + color: #707070; + font-size: 12px; +} +.calendar_timezone_text { + top: -10px; + left: -11px; + position: relative; + color: #707070; + font-size: 9px; +} +.calendar_hour_block { + display: flex; + flex-direction: row; + border-bottom: 1px solid #8d8d8d55; + position: relative; + 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; + padding-right: 0.3rem; + background-color: white; + border: 1px solid #8d8d8d55; + color: black; + font-weight: 600; + height: 8rem; + position: relative; +} +.day__outside { + /* background-color: #ededee !important; */ + color: #89898996 !important; +} +.day__selected { + background-color: #007bff; + color: #707070; +} +.day__today { + background-color: #def6e1; + font-weight: 700; + text-decoration: underline; + color: #31bb6b; +} +.day__events { + background-color: #def6e1; +} +/* yearly calender styling */ +.yearlyCalender { + background-color: #ffffff; + box-sizing: border-box; +} + +.circularButton { + width: 25px; + height: 25px; + border-radius: 50%; + background-color: rgba(255, 255, 255, 0); + border: none; + cursor: pointer; + margin-left: 0.75rem; +} +.circularButton:hover { + background-color: rgba(82, 172, 255, 0.5); +} +.closebtn { + padding: 10px; +} + +.yearlyCalendarHeader { + display: flex; + flex-direction: row; +} + +.yearlyCalendarHeader > div { + font-weight: 600; + font-size: 2rem; + padding: 0 10px; + color: #4b4b4b; +} +.noEventAvailable { + background-color: rgba(255, 255, 255, 0); +} + +.card { + /* box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2); */ + padding: 16px; + text-align: center; + /* background-color: #f1f1f1; */ + height: 21rem; +} +.cardHeader { + text-align: left; +} + +.row { + margin: 1px -5px; +} + +/* Clear floats after the columns */ +.row:after { + content: ''; + display: table; + clear: both; +} + +.weekday__yearly { + display: flex; + justify-content: center; + align-items: center; + /* color: #fff; */ + background-color: #ffffff; + font-weight: 600; +} +.day__yearly { + background-color: #ffffff; + padding-left: 0.3rem; + padding-right: 0.3rem; + background-color: white; + /* border: 1px solid #8d8d8d55; */ + color: #4b4b4b; + font-weight: 600; + height: 2rem; + position: relative; +} +* { + box-sizing: border-box; +} + +/* Float four columns side by side */ +.column { + float: left; + width: 25%; + padding: 10px; +} + +/* Remove extra left and right margins, due to padding */ +.row { + margin: 0 -5px; +} + +/* Clear floats after the columns */ +.row:after { + content: ''; + display: table; + clear: both; +} +/* yearly calender styling ends */ +.btn__today { + transition: ease-in all 200ms; + font-family: Arial; + color: #ffffff; + font-size: 18px; + padding: 10px 20px 10px 20px; + text-decoration: none; + margin-left: 20px; + border: none; +} +.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; +} + +.dropdown { + border-color: #31bb6b; + background-color: white; + color: #31bb6b; + box-shadow: 0px 2px 1px rgba(49, 187, 107, 0.5); /* Added blur effect */ +} + +.btnsContainer .input { + flex: 1; + position: relative; +} + +.btnsContainer input { + outline: 1px solid var(--bs-gray-400); +} + +.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; +} +.btn__more { + border: 0px; + font-size: 14px; + background-color: initial; + font-weight: 600; + transition: all 200ms; + position: relative; + display: block; + margin: -9px; + margin-top: -28px; +} +.btn__more:hover { + color: #3ce080; +} + +.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; +} +.expand_list_container { + width: 200px; + max-height: 250px; + z-index: 10; + position: absolute; + left: auto; + right: auto; + overflow: auto; + padding: 10px 4px 0px 4px; + background-color: rgb(241, 241, 241); + border: 1px solid rgb(201, 201, 201); + border-radius: 5px; + margin: 5px; +} +.flex_grow { + flex-grow: 1; +} + +@media only screen and (max-width: 700px) { + .event_list { + display: none; + } + .expand_list_container { + width: 150px; + padding: 4px 4px 0px 4px; + } + .day { + height: 5rem; + } +} + +@media only screen and (max-width: 500px) { + .btn__more { + font-size: 12px; + } + + .column { + float: left; + width: 100%; + padding: 10px; + } +} diff --git a/src/components/EventCalendar/YearlyEventCalender.tsx b/src/components/EventCalendar/YearlyEventCalender.tsx new file mode 100644 index 0000000000..7b7a4d4b03 --- /dev/null +++ b/src/components/EventCalendar/YearlyEventCalender.tsx @@ -0,0 +1,360 @@ +import EventListCard from 'components/EventListCard/EventListCard'; +import dayjs from 'dayjs'; +import Button from 'react-bootstrap/Button'; +import React, { useState, useEffect } from 'react'; +import styles from './YearlyEventCalender.module.css'; +import type { ViewType } from 'screens/OrganizationEvents/OrganizationEvents'; +import { ChevronLeft, ChevronRight } from '@mui/icons-material'; +import type { InterfaceRecurrenceRule } from 'utils/recurrenceUtils'; + +interface InterfaceEventListCardProps { + userRole?: string; + key?: string; + _id: string; + location: string; + title: string; + description: string; + startDate: string; + endDate: string; + startTime: string | null; + endTime: string | null; + allDay: boolean; + recurring: boolean; + recurrenceRule: InterfaceRecurrenceRule | null; + isRecurringEventException: boolean; + isPublic: boolean; + isRegisterable: boolean; + attendees?: { + _id: string; + }[]; + creator?: { + firstName: string; + lastName: string; + _id: string; + }; +} + +interface InterfaceCalendarProps { + eventData: InterfaceEventListCardProps[]; + refetchEvents?: () => void; + orgData?: InterfaceIOrgList; + userRole?: string; + userId?: string; + viewType?: ViewType; +} + +enum Status { + ACTIVE = 'ACTIVE', + BLOCKED = 'BLOCKED', + DELETED = 'DELETED', +} + +enum Role { + USER = 'USER', + SUPERADMIN = 'SUPERADMIN', + ADMIN = 'ADMIN', +} + +interface InterfaceIEventAttendees { + userId: string; + user?: string; + status?: Status; + createdAt?: Date; +} + +interface InterfaceIOrgList { + admins: { _id: string }[]; +} +const Calendar: React.FC = ({ + eventData, + refetchEvents, + orgData, + userRole, + userId, +}) => { + const [selectedDate] = useState(null); + const weekdaysShorthand = ['M', 'T', 'W', 'T', 'F', 'S', 'S']; + const months = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', + ]; + const today = new Date(); + const [currentYear, setCurrentYear] = useState(today.getFullYear()); + const [events, setEvents] = useState( + null, + ); + const [expandedY, setExpandedY] = useState(null); + + const filterData = ( + eventData: InterfaceEventListCardProps[], + orgData?: InterfaceIOrgList, + userRole?: string, + userId?: string, + ): InterfaceEventListCardProps[] => { + 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); + if (!event.isPublic) { + const filteredOrg: boolean | undefined = orgData?.admins?.some( + (data) => data._id === userId, + ); + + if (filteredOrg) { + data.push(event); + } + } + }); + } else { + eventData?.forEach((event) => { + if (event.isPublic) data.push(event); + const userAttending = event.attendees?.some( + (data) => data._id === userId, + ); + if (userAttending) { + data.push(event); + } + }); + } + return data; + }; + + useEffect(() => { + const data = filterData(eventData, orgData, userRole, userId); + setEvents(data); + }, [eventData, orgData, userRole, userId]); + + const handlePrevYear = (): void => { + /*istanbul ignore next*/ + setCurrentYear(currentYear - 1); + }; + + const handleNextYear = (): void => { + /*istanbul ignore next*/ + setCurrentYear(currentYear + 1); + }; + + const renderMonthDays = (): JSX.Element[] => { + const renderedMonths: JSX.Element[] = []; + + for (let monthInx = 0; monthInx < 12; monthInx++) { + const monthStart = new Date(currentYear, monthInx, 1); + const monthEnd = new Date(currentYear, monthInx + 1, 0); + + const startDate = new Date(monthStart); + const dayOfWeek = startDate.getDay(); + const diff = startDate.getDate() - dayOfWeek + (dayOfWeek === 0 ? -6 : 1); + startDate.setDate(diff); + + const endDate = new Date(monthEnd); + const endDayOfWeek = endDate.getDay(); + const diffEnd = + endDate.getDate() + (7 - endDayOfWeek) - (endDayOfWeek === 0 ? 7 : 0); + endDate.setDate(diffEnd); + + const days = []; + let currentDate = startDate; + while (currentDate <= endDate) { + days.push(currentDate); + currentDate = new Date( + currentDate.getFullYear(), + currentDate.getMonth(), + currentDate.getDate() + 1, + ); + } + + const renderedDays = days.map((date, dayIndex) => { + const className = [ + date.toLocaleDateString() === today.toLocaleDateString() + ? styles.day__today + : '', + date.getMonth() !== monthInx ? styles.day__outside : '', + selectedDate?.getTime() === date.getTime() + ? styles.day__selected + : '', + styles.day__yearly, + ].join(' '); + + const eventsForCurrentDate = events?.filter((event) => { + return dayjs(event.startDate).isSame(date, 'day'); + }); + + /*istanbul ignore next*/ + const renderedEvents = + eventsForCurrentDate?.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*/ + const toggleExpand = (index: string): void => { + if (expandedY === index) { + setExpandedY(null); + } else { + setExpandedY(index); + } + }; + + /*istanbul ignore next*/ + return ( +
    + {date.getDate()} +
    +
    + {expandedY === `${monthInx}-${dayIndex}` && renderedEvents} +
    + {renderedEvents && renderedEvents?.length > 0 && ( + + )} + {renderedEvents && renderedEvents?.length == 0 && ( + + )} +
    +
    + ); + }); + + renderedMonths.push( +
    +
    +
    {months[monthInx]}
    +
    + {weekdaysShorthand.map((weekday, index) => ( +
    + {weekday} +
    + ))} +
    +
    {renderedDays}
    +
    +
    , + ); + } + + return renderedMonths; + }; + + const renderYearlyCalendar = (): JSX.Element => { + return ( +
    +
    + +
    {currentYear}
    + +
    + +
    +
    {renderMonthDays()}
    +
    +
    + ); + }; + + return ( +
    +
    +
    {renderYearlyCalendar()}
    +
    +
    + ); +}; + +export default Calendar; diff --git a/src/components/EventCalendar/constants.js b/src/components/EventCalendar/constants.js new file mode 100644 index 0000000000..f2b770426c --- /dev/null +++ b/src/components/EventCalendar/constants.js @@ -0,0 +1,56 @@ +export const holidays = [ + { name: 'May Day / Labour Day', date: '05-01', month: 'May' }, // May 1st + { name: "Mother's Day", date: '05-08', month: 'May' }, // Second Sunday in May + { name: "Father's Day", date: '06-19', month: 'June' }, // Third Sunday in June + { name: 'Independence Day (US)', date: '07-04', month: 'July' }, // July 4th + { name: 'Oktoberfest', date: '09-21', month: 'September' }, // September 21st (starts in September, ends in October) + { name: 'Halloween', date: '10-31', month: 'October' }, // October 31st + { name: 'Diwali', date: '11-04', month: 'November' }, + { + name: 'Remembrance Day / Veterans Day', + date: '11-11', + month: 'November', + }, + { name: 'Christmas Day', date: '12-25', month: 'December' }, // December 25th +]; +export const weekdays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; +export const months = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', +]; +export const hours = [ + '12 AM', + '01 AM', + '02 AM', + '03 AM', + '04 AM', + '05 AM', + '06 AM', + '07 AM', + '08 AM', + '09 AM', + '10 AM', + '11 AM', + '12 PM', + '01 PM', + '02 PM', + '03 PM', + '04 PM', + '05 PM', + '06 PM', + '07 PM', + '08 PM', + '09 PM', + '10 PM', + '11 PM', +]; diff --git a/src/components/EventDashboardScreen/EventDashboardScreen.module.css b/src/components/EventDashboardScreen/EventDashboardScreen.module.css new file mode 100644 index 0000000000..33c642dd95 --- /dev/null +++ b/src/components/EventDashboardScreen/EventDashboardScreen.module.css @@ -0,0 +1,198 @@ +.gap { + gap: 20px; +} + +.mainContainer { + width: 50%; + flex-grow: 3; + padding: 20px; + max-height: 100%; + overflow: auto; +} + +.containerHeight { + height: calc(100vh - 66px); +} + +.colorLight { + background-color: #f1f3f6; +} + +.pageContainer { + display: flex; + flex-direction: column; + min-height: 100vh; + padding: 1rem 1.5rem 0 calc(300px + 2rem + 1.5rem); +} + +.expand { + padding-left: 4rem; + animation: moveLeft 0.5s ease-in-out; +} +.avatarStyle { + border-radius: 100%; +} +.profileContainer { + border: none; + padding: 2.1rem 0.5rem; + height: 52px; + border-radius: 8px 0px 0px 8px; + display: flex; + align-items: center; + background-color: white !important; + box-shadow: + 0 4px 4px 0 rgba(177, 177, 177, 0.2), + 0 6px 20px 0 rgba(151, 151, 151, 0.19); +} +.profileContainer:focus { + outline: none; + background-color: var(--bs-gray-100); +} +.imageContainer { + width: 56px; +} +.profileContainer .profileText { + flex: 1; + text-align: start; + overflow: hidden; + margin-right: 4px; +} +.angleDown { + margin-left: 4px; +} +.profileContainer .profileText .primaryText { + font-size: 1rem; + font-weight: 600; + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 2; /* number of lines to show */ + -webkit-box-orient: vertical; + word-wrap: break-word; + white-space: normal; +} +.profileContainer .profileText .secondaryText { + font-size: 0.8rem; + font-weight: 400; + color: var(--bs-secondary); + display: block; + text-transform: capitalize; +} + +.contract { + padding-left: calc(300px + 2rem + 1.5rem); + animation: moveRight 0.5s ease-in-out; +} + +.collapseSidebarButton { + position: fixed; + height: 40px; + bottom: 0; + z-index: 9999; + width: calc(300px + 2rem); + background-color: rgba(245, 245, 245, 0.7); + color: black; + border: none; + border-radius: 0px; +} + +.collapseSidebarButton:hover, +.opendrawer:hover { + opacity: 1; + color: black !important; +} +.opendrawer { + position: fixed; + display: flex; + align-items: center; + justify-content: center; + top: 0; + left: 0; + width: 40px; + height: 100vh; + z-index: 9999; + background-color: rgba(245, 245, 245); + border: none; + border-radius: 0px; + margin-right: 20px; + color: black; +} +.profileDropdown { + background-color: transparent !important; +} +.profileDropdown .dropdown-toggle .btn .btn-normal { + display: none !important; + background-color: transparent !important; +} +.dropdownToggle { + background-image: url(/public/images/svg/angleDown.svg); + background-repeat: no-repeat; + background-position: center; + background-color: azure; +} + +.dropdownToggle::after { + border-top: none !important; + border-bottom: none !important; +} + +.opendrawer:hover { + transition: background-color 0.5s ease; + background-color: var(--bs-primary); +} +.collapseSidebarButton:hover { + transition: background-color 0.5s ease; + background-color: var(--bs-primary); +} + +@media (max-width: 1120px) { + .contract { + padding-left: calc(250px + 2rem + 1.5rem); + } + .collapseSidebarButton { + width: calc(250px + 2rem); + } +} + +@media (max-height: 900px) { + .pageContainer { + padding: 1rem 1.5rem 0 calc(300px + 2rem); + } + .collapseSidebarButton { + height: 30px; + width: calc(300px + 1rem); + } +} +@media (max-height: 650px) { + .pageContainer { + padding: 1rem 1.5rem 0 calc(270px); + } + .collapseSidebarButton { + width: 250px; + height: 20px; + } + .opendrawer { + width: 30px; + } +} + +/* For tablets */ +@media (max-width: 820px) { + .pageContainer { + padding-left: 2.5rem; + } + + .opendrawer { + width: 25px; + } + + .contract, + .expand { + animation: none; + } + + .collapseSidebarButton { + width: 100%; + left: 0; + right: 0; + } +} diff --git a/src/components/EventDashboardScreen/EventDashboardScreen.test.tsx b/src/components/EventDashboardScreen/EventDashboardScreen.test.tsx new file mode 100644 index 0000000000..6b48b034a9 --- /dev/null +++ b/src/components/EventDashboardScreen/EventDashboardScreen.test.tsx @@ -0,0 +1,166 @@ +import React from 'react'; +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 { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; +import EventDashboardScreen from './EventDashboardScreen'; +import { ORGANIZATIONS_LIST } from 'GraphQl/Queries/Queries'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import useLocalStorage from 'utils/useLocalstorage'; +const { setItem } = useLocalStorage(); + +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(), + })), +}); + +let mockID: string | undefined = '123'; +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: mockID }), +})); + +const MOCKS = [ + { + request: { + query: ORGANIZATIONS_LIST, + variables: { id: '123' }, + }, + result: { + data: { + organizations: [ + { + _id: '123', + image: null, + creator: { + firstName: 'John', + lastName: 'Doe', + email: 'JohnDoe@example.com', + }, + name: 'Test Organization', + description: 'Testing this organization', + address: { + city: 'Mountain View', + countryCode: 'US', + dependentLocality: 'Some Dependent Locality', + line1: '123 Main Street', + line2: 'Apt 456', + postalCode: '94040', + sortingCode: 'XYZ-789', + state: 'CA', + }, + userRegistrationRequired: true, + visibleInSearch: true, + members: [], + admins: [], + membershipRequests: [], + blockedUsers: [], + }, + ], + }, + }, + }, +]; +const link = new StaticMockLink(MOCKS, true); + +const resizeWindow = (width: number): void => { + window.innerWidth = width; + fireEvent(window, new Event('resize')); +}; + +const clickToggleMenuBtn = (toggleButton: HTMLElement): void => { + fireEvent.click(toggleButton); +}; + +describe('Testing LeftDrawer in OrganizationScreen', () => { + test('should be redirected to / if IsLoggedIn is false', async () => { + setItem('IsLoggedIn', false); + render( + + + + + + + + + , + ); + expect(window.location.pathname).toEqual('/'); + }); + test('should be redirected to / if ss is false', async () => { + setItem('IsLoggedIn', true); + render( + + + + + + + + + , + ); + }); + test('Testing LeftDrawer in page functionality', async () => { + setItem('IsLoggedIn', true); + setItem('AdminFor', [ + { _id: '6637904485008f171cf29924', __typename: 'Organization' }, + ]); + render( + + + + + + + + + , + ); + const toggleButton = screen.getByTestId('toggleMenuBtn') as HTMLElement; + const icon = toggleButton.querySelector('i'); + + // Resize window to a smaller width + resizeWindow(800); + clickToggleMenuBtn(toggleButton); + expect(icon).toHaveClass('fa fa-angle-double-right'); + // Resize window back to a larger width + + resizeWindow(1000); + clickToggleMenuBtn(toggleButton); + expect(icon).toHaveClass('fa fa-angle-double-left'); + + clickToggleMenuBtn(toggleButton); + expect(icon).toHaveClass('fa fa-angle-double-right'); + }); + + test('should be redirected to / if orgId is undefined', async () => { + mockID = undefined; + render( + + + + + + + + + , + ); + expect(window.location.pathname).toEqual('/'); + }); +}); diff --git a/src/components/EventDashboardScreen/EventDashboardScreen.tsx b/src/components/EventDashboardScreen/EventDashboardScreen.tsx new file mode 100644 index 0000000000..9b518f5e0b --- /dev/null +++ b/src/components/EventDashboardScreen/EventDashboardScreen.tsx @@ -0,0 +1,144 @@ +import LeftDrawerOrg from 'components/LeftDrawerOrg/LeftDrawerOrg'; +import React, { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useDispatch, useSelector } from 'react-redux'; +import { Navigate, Outlet, useLocation, useParams } from 'react-router-dom'; +import { updateTargets } from 'state/action-creators'; +import type { RootState } from 'state/reducers'; +import type { TargetsType } from 'state/reducers/routesReducer'; +import styles from './EventDashboardScreen.module.css'; +import ProfileDropdown from 'components/ProfileDropdown/ProfileDropdown'; +import useLocalStorage from 'utils/useLocalstorage'; + +const EventDashboardScreen = (): JSX.Element => { + const { getItem } = useLocalStorage(); + const isLoggedIn = getItem('IsLoggedIn'); + const adminFor = getItem('AdminFor'); + const location = useLocation(); + const titleKey: string | undefined = map[location.pathname.split('/')[2]]; + const { t } = useTranslation('translation', { keyPrefix: titleKey }); + const [hideDrawer, setHideDrawer] = useState(null); + const { orgId } = useParams(); + if (!orgId) { + return ; + } + + if (isLoggedIn === false) return ; + if (adminFor === null) { + return ( + <> +
    +
    +
    +
    +

    {t('title')}

    +
    + +
    +
    +
    + + ); + } + + const appRoutes: { + targets: TargetsType[]; + } = useSelector((state: RootState) => state.appRoutes); + const { targets } = appRoutes; + + const dispatch = useDispatch(); + useEffect(() => { + dispatch(updateTargets(orgId)); + }, [orgId]); // Added orgId to the dependency array + + const handleResize = (): void => { + if (window.innerWidth <= 820 && !hideDrawer) { + setHideDrawer(true); + } + }; + + const toggleDrawer = (): void => { + setHideDrawer(!hideDrawer); + }; + + useEffect(() => { + handleResize(); + window.addEventListener('resize', handleResize); + return () => { + window.removeEventListener('resize', handleResize); + }; + }, [hideDrawer]); + + return ( + <> + +
    + +
    +
    +
    +
    +

    {t('title')}

    +
    + +
    + +
    + + ); +}; + +export default EventDashboardScreen; + +interface InterfaceMapType { + [key: string]: string; +} + +const map: InterfaceMapType = { + orgdash: 'dashboard', + orgpeople: 'organizationPeople', + requests: 'requests', + orgads: 'advertisement', + member: 'memberDetail', + orgevents: 'organizationEvents', + orgactionitems: 'organizationActionItems', + orgcontribution: 'orgContribution', + orgpost: 'orgPost', + orgfunds: 'funds', + orgfundcampaign: 'fundCampaign', + fundCampaignPledge: 'pledges', + orgsetting: 'orgSettings', + orgstore: 'addOnStore', + blockuser: 'blockUnblockUser', + orgvenues: 'organizationVenues', + event: 'eventManagement', +}; diff --git a/src/components/EventListCard/EventListCard.module.css b/src/components/EventListCard/EventListCard.module.css new file mode 100644 index 0000000000..1e47972a42 --- /dev/null +++ b/src/components/EventListCard/EventListCard.module.css @@ -0,0 +1,223 @@ +.cards h2 { + font-size: 15px; + color: #4e4c4c; + font-weight: 500; +} +.cards > h3 { + font-size: 17px; +} +.cards > p { + font-size: 14px; + margin-top: 0px; + margin-bottom: 7px; +} +.cards a { + color: #fff; + font-weight: 600; +} +.cards a:hover { + color: black; +} +.cards { + position: relative; + overflow: hidden; + transition: all 0.3s; + margin-bottom: 5px; +} +.dispflex { + display: flex; + cursor: pointer; + justify-content: space-between; + margin: 10px 5px 5px 0px; +} +.eventtitle { + margin-bottom: 0px; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} +.iconContainer { + display: flex; + justify-content: flex-end; +} +.icon { + margin: 2px; +} + +.cards { + width: 100%; + background: #5cacf7 !important; + padding: 2px 3px; + border-radius: 5px; + border: 1px solid #e8e8e8; + box-shadow: 0 3px 2px #e8e8e8; + color: #737373; + box-sizing: border-box; +} +.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; +} + +.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; +} +.datediv { + display: flex; + flex-direction: row; + margin-top: 5px; + margin-bottom: 5px; +} +.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; +} +.datediv > div > p { + margin-bottom: 0.5rem; +} + +.startDate { + margin-right: 0.25rem; +} +.endDate { + margin-left: 1.5rem; +} + +.checkboxdiv > div label { + margin-right: 50px; +} +.checkboxdiv > label > input { + margin-left: 10px; +} + +.dispflex > input { + width: 20%; + border: none; + box-shadow: none; + margin-top: 5px; +} + +.checkboxContainer { + display: flex; + justify-content: space-between; +} + +.checkboxdiv { + display: flex; + flex-direction: column; +} + +.preview { + display: flex; + flex-direction: row; + font-weight: 700; + font-size: 16px; + color: #000000; + margin: 0; +} +.view { + margin-left: 2%; + font-weight: 600; + font-size: 16px; + color: #707070; +} +.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: 20px 30px; + background: #ffffff; + border-color: #e8e5e5; + border-width: 5px; + border-radius: 10px; + width: 40%; +} + +.form_wrapper form { + display: flex; + align-items: left; + justify-content: left; + flex-direction: column; +} +.titlemodal { + color: #000000; + font-weight: 600; + font-size: 24px; + margin-bottom: 20px; + padding-bottom: 5px; + border-bottom: 4px solid #31bb6b; + width: 50%; +} +.cancel > i { + margin-top: 5px; + transform: scale(1.2); + cursor: pointer; + color: #707070; +} +.modalbody { + width: 50px; +} +.list_box { + height: 70vh; + overflow-y: auto; + width: auto; +} +@media only screen and (max-width: 600px) { + .form_wrapper { + width: 90%; + top: 45%; + } + .checkboxContainer { + flex-direction: column; + } + + .datediv { + flex-direction: column; + } + + .datediv > div { + width: 100%; + margin-left: 0; + margin-bottom: 10px; + } + + .datediv > div p { + margin-bottom: 5px; + } +} + +.customButton { + width: 90%; + margin: 0 auto; +} diff --git a/src/components/EventListCard/EventListCard.test.tsx b/src/components/EventListCard/EventListCard.test.tsx new file mode 100644 index 0000000000..22ddccd8d2 --- /dev/null +++ b/src/components/EventListCard/EventListCard.test.tsx @@ -0,0 +1,947 @@ +import React from 'react'; +import type { RenderResult } from '@testing-library/react'; +import { + act, + render, + screen, + fireEvent, + waitFor, +} from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import userEvent from '@testing-library/user-event'; +import { I18nextProvider } from 'react-i18next'; +import type { InterfaceEventListCardProps } from './EventListCard'; +import EventListCard from './EventListCard'; +import i18n from 'utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { BrowserRouter, MemoryRouter, Route, Routes } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import { toast } from 'react-toastify'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import useLocalStorage from 'utils/useLocalstorage'; +import { props } from './EventListCardProps'; +import { ERROR_MOCKS, MOCKS } from './EventListCardMocks'; + +const { setItem } = useLocalStorage(); + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(ERROR_MOCKS, true); + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const translations = { + ...JSON.parse( + JSON.stringify( + i18n.getDataByLanguage('en')?.translation.eventListCard ?? {}, + ), + ), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), +}; + +const renderEventListCard = ( + props: InterfaceEventListCardProps, +): RenderResult => { + return render( + + + + + + + } + /> + } + /> + Event Dashboard (Admin)
    } + /> + Event Dashboard (User)
    } + /> + + + + + + , + ); +}; + +describe('Testing Event List Card', () => { + const updateData = { + title: 'Updated title', + description: 'This is a new update', + isPublic: true, + recurring: false, + isRegisterable: true, + allDay: false, + location: 'New Delhi', + startDate: '03/18/2022', + endDate: '03/20/2022', + startTime: '09:00 AM', + endTime: '05:00 PM', + }; + + beforeAll(() => { + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: 'orgId' }), + })); + }); + + afterAll(() => { + localStorage.clear(); + jest.clearAllMocks(); + }); + + test('Testing for event modal', async () => { + renderEventListCard(props[1]); + + userEvent.click(screen.getByTestId('card')); + + await waitFor(() => { + expect(screen.getByTestId('eventModalCloseBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('eventModalCloseBtn')); + + await waitFor(() => { + expect( + screen.queryByTestId('eventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('Should navigate to "/" if orgId is not defined', async () => { + render( + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(window.location.pathname).toEqual('/'); + }); + }); + + test('Should render default text if event details are null', async () => { + renderEventListCard(props[0]); + + await waitFor(() => { + expect(screen.getByText('Dogs Care')).toBeInTheDocument(); + }); + }); + + test('should render props and text elements test for the screen', async () => { + renderEventListCard(props[1]); + + expect(screen.getByText(props[1].eventName)).toBeInTheDocument(); + + userEvent.click(screen.getByTestId('card')); + + await waitFor(() => { + expect(screen.getByTestId('updateDescription')).toBeInTheDocument(); + }); + + expect(screen.getByTestId('updateDescription')).toHaveValue( + props[1].eventDescription, + ); + expect(screen.getByTestId('updateLocation')).toHaveValue( + props[1].eventLocation, + ); + + userEvent.click(screen.getByTestId('eventModalCloseBtn')); + + await waitFor(() => { + expect( + screen.queryByTestId('eventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('Should render truncated event name when length is more than 100', async () => { + const longEventName = 'a'.repeat(101); + renderEventListCard({ ...props[1], eventName: longEventName }); + + userEvent.click(screen.getByTestId('card')); + + await waitFor(() => { + expect(screen.getByTestId('updateTitle')).toBeInTheDocument(); + }); + + expect(screen.getByTestId('updateTitle')).toHaveValue( + `${longEventName.substring(0, 100)}...`, + ); + + userEvent.click(screen.getByTestId('eventModalCloseBtn')); + + await waitFor(() => { + expect( + screen.queryByTestId('eventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('Should render full event name when length is less than or equal to 100', async () => { + const shortEventName = 'a'.repeat(100); + renderEventListCard({ ...props[1], eventName: shortEventName }); + + userEvent.click(screen.getByTestId('card')); + + await waitFor(() => { + expect(screen.getByTestId('updateTitle')).toBeInTheDocument(); + }); + + expect(screen.getByTestId('updateTitle')).toHaveValue(shortEventName); + + userEvent.click(screen.getByTestId('eventModalCloseBtn')); + + await waitFor(() => { + expect( + screen.queryByTestId('eventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('Should render truncated event description when length is more than 256', async () => { + const longEventDescription = 'a'.repeat(257); + + renderEventListCard({ + ...props[1], + eventDescription: longEventDescription, + }); + + userEvent.click(screen.getByTestId('card')); + + await waitFor(() => { + expect(screen.getByTestId('updateDescription')).toBeInTheDocument(); + }); + expect(screen.getByTestId('updateDescription')).toHaveValue( + `${longEventDescription.substring(0, 256)}...`, + ); + + userEvent.click(screen.getByTestId('eventModalCloseBtn')); + + await waitFor(() => { + expect( + screen.queryByTestId('eventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('Should render full event description when length is less than or equal to 256', async () => { + const shortEventDescription = 'a'.repeat(256); + + renderEventListCard({ + ...props[1], + eventDescription: shortEventDescription, + }); + + userEvent.click(screen.getByTestId('card')); + + await waitFor(() => { + expect(screen.getByTestId('updateDescription')).toBeInTheDocument(); + }); + expect(screen.getByTestId('updateDescription')).toHaveValue( + shortEventDescription, + ); + + userEvent.click(screen.getByTestId('eventModalCloseBtn')); + + await waitFor(() => { + expect( + screen.queryByTestId('eventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('Should navigate to event dashboard when clicked (For Admin)', async () => { + renderEventListCard(props[1]); + + userEvent.click(screen.getByTestId('card')); + + await waitFor(() => { + expect(screen.getByTestId('showEventDashboardBtn')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('showEventDashboardBtn')); + + await waitFor(() => { + expect(screen.queryByTestId('card')).not.toBeInTheDocument(); + expect(screen.queryByText('Event Dashboard (Admin)')).toBeInTheDocument(); + }); + }); + + test('Should navigate to event dashboard when clicked (For User)', async () => { + setItem('userId', '123'); + renderEventListCard(props[2]); + + userEvent.click(screen.getByTestId('card')); + + await waitFor(() => { + expect(screen.getByTestId('showEventDashboardBtn')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('showEventDashboardBtn')); + + await waitFor(() => { + expect(screen.queryByTestId('card')).not.toBeInTheDocument(); + expect(screen.queryByText('Event Dashboard (User)')).toBeInTheDocument(); + }); + }); + + test('Should update a non-recurring event', async () => { + renderEventListCard(props[1]); + + userEvent.click(screen.getByTestId('card')); + + const eventTitle = screen.getByTestId('updateTitle'); + fireEvent.change(eventTitle, { target: { value: '' } }); + userEvent.type(eventTitle, updateData.title); + + const eventDescription = screen.getByTestId('updateDescription'); + fireEvent.change(eventDescription, { target: { value: '' } }); + userEvent.type(eventDescription, updateData.description); + + const eventLocation = screen.getByTestId('updateLocation'); + fireEvent.change(eventLocation, { target: { value: '' } }); + userEvent.type(eventLocation, updateData.location); + + const startDatePicker = screen.getByLabelText(translations.startDate); + fireEvent.change(startDatePicker, { + target: { value: updateData.startDate }, + }); + + const endDatePicker = screen.getByLabelText(translations.endDate); + fireEvent.change(endDatePicker, { + target: { value: updateData.endDate }, + }); + + userEvent.click(screen.getByTestId('updateAllDay')); + userEvent.click(screen.getByTestId('updateIsPublic')); + userEvent.click(screen.getByTestId('updateRegistrable')); + userEvent.click(screen.getByTestId('updateEventBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.eventUpdated); + }); + + await waitFor(() => { + expect( + screen.queryByTestId('eventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('Should update a non all day non-recurring event', async () => { + renderEventListCard(props[1]); + + userEvent.click(screen.getByTestId('card')); + + const eventTitle = screen.getByTestId('updateTitle'); + fireEvent.change(eventTitle, { target: { value: '' } }); + userEvent.type(eventTitle, updateData.title); + + const eventDescription = screen.getByTestId('updateDescription'); + fireEvent.change(eventDescription, { target: { value: '' } }); + userEvent.type(eventDescription, updateData.description); + + const eventLocation = screen.getByTestId('updateLocation'); + fireEvent.change(eventLocation, { target: { value: '' } }); + userEvent.type(eventLocation, updateData.location); + + const startDatePicker = screen.getByLabelText(translations.startDate); + fireEvent.change(startDatePicker, { + target: { value: updateData.startDate }, + }); + + const endDatePicker = screen.getByLabelText(translations.endDate); + fireEvent.change(endDatePicker, { + target: { value: updateData.endDate }, + }); + + const startTimePicker = screen.getByLabelText(translations.startTime); + fireEvent.change(startTimePicker, { + target: { value: updateData.startTime }, + }); + + const endTimePicker = screen.getByLabelText(translations.endTime); + fireEvent.change(endTimePicker, { + target: { value: updateData.endTime }, + }); + + userEvent.click(screen.getByTestId('updateIsPublic')); + userEvent.click(screen.getByTestId('updateRegistrable')); + + userEvent.click(screen.getByTestId('updateEventBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.eventUpdated); + }); + + await waitFor(() => { + expect( + screen.queryByTestId('eventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('should update a single event to be recurring', async () => { + renderEventListCard(props[1]); + + userEvent.click(screen.getByTestId('card')); + + const eventTitle = screen.getByTestId('updateTitle'); + fireEvent.change(eventTitle, { target: { value: '' } }); + userEvent.type(eventTitle, updateData.title); + + const eventDescription = screen.getByTestId('updateDescription'); + fireEvent.change(eventDescription, { target: { value: '' } }); + userEvent.type(eventDescription, updateData.description); + + const eventLocation = screen.getByTestId('updateLocation'); + fireEvent.change(eventLocation, { target: { value: '' } }); + userEvent.type(eventLocation, updateData.location); + + const startDatePicker = screen.getByLabelText(translations.startDate); + fireEvent.change(startDatePicker, { + target: { value: updateData.startDate }, + }); + + const endDatePicker = screen.getByLabelText(translations.endDate); + fireEvent.change(endDatePicker, { + target: { value: updateData.endDate }, + }); + + userEvent.click(screen.getByTestId('updateAllDay')); + userEvent.click(screen.getByTestId('updateRecurring')); + userEvent.click(screen.getByTestId('updateIsPublic')); + userEvent.click(screen.getByTestId('updateRegistrable')); + userEvent.click(screen.getByTestId('updateEventBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.eventUpdated); + }); + + await waitFor(() => { + expect( + screen.queryByTestId('eventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('should show different update options for a recurring event based on different conditions', async () => { + renderEventListCard(props[5]); + + userEvent.click(screen.getByTestId('card')); + + await waitFor(() => { + expect(screen.queryByTestId('updateEventBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('updateEventBtn')); + + // shows options to update thisInstance and thisAndFollowingInstances, and allInstances + await waitFor(() => { + expect(screen.getByTestId('update-thisInstance')).toBeInTheDocument(); + expect( + screen.getByTestId('update-thisAndFollowingInstances'), + ).toBeInTheDocument(); + expect(screen.getByTestId('update-allInstances')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('eventUpdateOptionsModalCloseBtn')); + + await waitFor(() => { + expect(screen.getByLabelText(translations.startDate)).toBeInTheDocument(); + }); + + // change the event dates + let startDatePicker = screen.getByLabelText(translations.startDate); + fireEvent.change(startDatePicker, { + target: { value: updateData.startDate }, + }); + + let endDatePicker = screen.getByLabelText(translations.endDate); + fireEvent.change(endDatePicker, { + target: { value: updateData.endDate }, + }); + + userEvent.click(screen.getByTestId('updateEventBtn')); + + // shows options to update thisInstance and thisAndFollowingInstances only + await waitFor(() => { + expect(screen.getByTestId('update-thisInstance')).toBeInTheDocument(); + expect( + screen.getByTestId('update-thisAndFollowingInstances'), + ).toBeInTheDocument(); + expect( + screen.queryByTestId('update-allInstances'), + ).not.toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('eventUpdateOptionsModalCloseBtn')); + + await waitFor(() => { + expect(screen.getByLabelText(translations.startDate)).toBeInTheDocument(); + }); + + // reset the event dates to their original values + startDatePicker = screen.getByLabelText(translations.startDate); + fireEvent.change(startDatePicker, { + target: { value: '03/17/2022' }, + }); + + endDatePicker = screen.getByLabelText(translations.endDate); + fireEvent.change(endDatePicker, { + target: { value: '03/17/2022' }, + }); + + // now change the recurrence rule of the event + await waitFor(() => { + expect(screen.getByTestId('recurrenceOptions')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('recurrenceOptions')); + + await waitFor(() => { + expect(screen.getByTestId('customRecurrence')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('customRecurrence')); + + await waitFor(() => { + expect( + screen.getByTestId('customRecurrenceFrequencyDropdown'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('customRecurrenceFrequencyDropdown')); + + await waitFor(() => { + expect(screen.getByTestId('customDailyRecurrence')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('customDailyRecurrence')); + + await waitFor(() => { + expect( + screen.getByTestId('customRecurrenceSubmitBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('customRecurrenceSubmitBtn')); + + await waitFor(() => { + expect(screen.getByTestId('updateEventBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('updateEventBtn')); + + // shows options to update thisAndFollowingInstances and allInstances only + await waitFor(() => { + expect( + screen.queryByTestId('update-thisInstance'), + ).not.toBeInTheDocument(); + expect( + screen.getByTestId('update-thisAndFollowingInstances'), + ).toBeInTheDocument(); + expect(screen.queryByTestId('update-allInstances')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('eventUpdateOptionsModalCloseBtn')); + + await waitFor(() => { + expect(screen.getByTestId('eventModalCloseBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('eventModalCloseBtn')); + + await waitFor(() => { + expect( + screen.queryByTestId('eventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('should show recurrenceRule as changed if the recurrence weekdays have changed', async () => { + renderEventListCard(props[4]); + + userEvent.click(screen.getByTestId('card')); + + await waitFor(() => { + expect(screen.getByTestId('recurrenceOptions')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('recurrenceOptions')); + + await waitFor(() => { + expect(screen.getByTestId('customRecurrence')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('customRecurrence')); + + // since the current recurrence weekDay for the current recurring event is "SATURDAY", + // let's first deselect it, and then we'll select a different day + // the recurrence rule should be marked as changed and we should see the option to update + // thisAndFollowingInstances and allInstances only + await waitFor(() => { + expect(screen.getAllByTestId('recurrenceWeekDay')[6]).toBeInTheDocument(); + }); + + // deselect saturday, which is the 7th day in recurrenceWeekDay options + userEvent.click(screen.getAllByTestId('recurrenceWeekDay')[6]); + + // select a different day, say wednesday, the 4th day in recurrenceWeekDay options + userEvent.click(screen.getAllByTestId('recurrenceWeekDay')[3]); + + userEvent.click(screen.getByTestId('customRecurrenceSubmitBtn')); + + await waitFor(() => { + expect(screen.getByTestId('updateEventBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('updateEventBtn')); + + // shows options to update thisInstance and thisAndFollowingInstances, and allInstances + await waitFor(() => { + expect( + screen.queryByTestId('update-thisInstance'), + ).not.toBeInTheDocument(); + expect( + screen.getByTestId('update-thisAndFollowingInstances'), + ).toBeInTheDocument(); + expect(screen.getByTestId('update-allInstances')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('eventUpdateOptionsModalCloseBtn')); + + await waitFor(() => { + expect(screen.getByTestId('eventModalCloseBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('eventModalCloseBtn')); + + await waitFor(() => { + expect( + screen.queryByTestId('eventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('should update all instances of a recurring event', async () => { + renderEventListCard(props[6]); + + userEvent.click(screen.getByTestId('card')); + + await waitFor(() => { + expect(screen.getByTestId('updateTitle')).toBeInTheDocument(); + }); + + const eventTitle = screen.getByTestId('updateTitle'); + fireEvent.change(eventTitle, { target: { value: '' } }); + userEvent.type(eventTitle, updateData.title); + + const eventDescription = screen.getByTestId('updateDescription'); + fireEvent.change(eventDescription, { target: { value: '' } }); + userEvent.type(eventDescription, updateData.description); + + const eventLocation = screen.getByTestId('updateLocation'); + fireEvent.change(eventLocation, { target: { value: '' } }); + userEvent.type(eventLocation, updateData.location); + + userEvent.click(screen.getByTestId('updateEventBtn')); + + // shows options to update thisInstance and thisAndFollowingInstances, and allInstances + await waitFor(() => { + expect(screen.getByTestId('update-thisInstance')).toBeInTheDocument(); + expect( + screen.getByTestId('update-thisAndFollowingInstances'), + ).toBeInTheDocument(); + expect(screen.getByTestId('update-allInstances')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('update-allInstances')); + userEvent.click(screen.getByTestId('recurringEventUpdateOptionSubmitBtn')); + + await waitFor(() => { + expect(screen.getByTestId('updateEventBtn')).toBeInTheDocument(); + }); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.eventUpdated); + }); + + await waitFor(() => { + expect( + screen.queryByTestId('eventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('should update thisAndFollowingInstances of a recurring event', async () => { + renderEventListCard(props[5]); + + userEvent.click(screen.getByTestId('card')); + + await waitFor(() => { + expect(screen.getByLabelText(translations.startDate)).toBeInTheDocument(); + }); + + // change the event dates + const startDatePicker = screen.getByLabelText(translations.startDate); + fireEvent.change(startDatePicker, { + target: { value: updateData.startDate }, + }); + + const endDatePicker = screen.getByLabelText(translations.endDate); + fireEvent.change(endDatePicker, { + target: { value: updateData.endDate }, + }); + + // now change the recurrence rule of the event + await waitFor(() => { + expect(screen.getByTestId('recurrenceOptions')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('recurrenceOptions')); + + await waitFor(() => { + expect(screen.getByTestId('customRecurrence')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('customRecurrence')); + + await waitFor(() => { + expect( + screen.getByTestId('customRecurrenceFrequencyDropdown'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('customRecurrenceFrequencyDropdown')); + + await waitFor(() => { + expect(screen.getByTestId('customDailyRecurrence')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('customDailyRecurrence')); + + await waitFor(() => { + expect( + screen.getByTestId('customRecurrenceSubmitBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('customRecurrenceSubmitBtn')); + + await waitFor(() => { + expect(screen.getByTestId('updateEventBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('updateEventBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.eventUpdated); + }); + + await waitFor(() => { + expect( + screen.queryByTestId('eventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('should render the delete modal', async () => { + renderEventListCard(props[1]); + + userEvent.click(screen.getByTestId('card')); + + await waitFor(() => { + expect(screen.getByTestId('deleteEventModalBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteEventModalBtn')); + + await waitFor(() => { + expect( + screen.getByTestId('eventDeleteModalCloseBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('eventDeleteModalCloseBtn')); + + await waitFor(() => { + expect( + screen.queryByTestId('eventDeleteModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + + await waitFor(() => { + expect(screen.getByTestId('eventModalCloseBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('eventModalCloseBtn')); + + await waitFor(() => { + expect( + screen.queryByTestId('eventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('should call the delete event mutation when the "Yes" button is clicked', async () => { + renderEventListCard(props[1]); + + userEvent.click(screen.getByTestId('card')); + + await waitFor(() => { + expect(screen.getByTestId('deleteEventModalBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteEventModalBtn')); + + await waitFor(() => { + expect(screen.getByTestId('deleteEventBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteEventBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.eventDeleted); + }); + + await waitFor(() => { + expect( + screen.queryByTestId('eventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('select different delete options on recurring events & then delete the recurring event', async () => { + renderEventListCard(props[4]); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('card')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('card')); + + await waitFor(() => { + expect(screen.getByTestId('deleteEventModalBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteEventModalBtn')); + + await waitFor(() => { + expect( + screen.getByTestId('delete-thisAndFollowingInstances'), + ).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('delete-thisAndFollowingInstances')); + + userEvent.click(screen.getByTestId('delete-allInstances')); + userEvent.click(screen.getByTestId('delete-thisInstance')); + + userEvent.click(screen.getByTestId('deleteEventBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.eventDeleted); + }); + + await waitFor(() => { + expect( + screen.queryByTestId('eventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('should show an error toast when the delete event mutation fails', async () => { + render( + + + + + + + } + /> + } + /> + + + + + + , + ); + + userEvent.click(screen.getByTestId('card')); + userEvent.click(screen.getByTestId('deleteEventModalBtn')); + userEvent.click(screen.getByTestId('deleteEventBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); + + test('handle register should work properly', async () => { + setItem('userId', '456'); + + renderEventListCard(props[2]); + + userEvent.click(screen.getByTestId('card')); + + await waitFor(() => { + expect(screen.getByTestId('registerEventBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('registerEventBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith( + `Successfully registered for ${props[2].eventName}`, + ); + }); + + await waitFor(() => { + expect( + screen.queryByTestId('eventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('should show already registered text when the user is registered for an event', async () => { + renderEventListCard(props[3]); + + userEvent.click(screen.getByTestId('card')); + + expect( + screen.getByText(translations.alreadyRegistered), + ).toBeInTheDocument(); + }); +}); diff --git a/src/components/EventListCard/EventListCard.tsx b/src/components/EventListCard/EventListCard.tsx new file mode 100644 index 0000000000..9d89647ee1 --- /dev/null +++ b/src/components/EventListCard/EventListCard.tsx @@ -0,0 +1,85 @@ +import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import styles from './EventListCard.module.css'; +import { Navigate, useParams } from 'react-router-dom'; +import EventListCardModals from './EventListCardModals'; +import type { InterfaceRecurrenceRule } from 'utils/recurrenceUtils'; + +export interface InterfaceEventListCardProps { + refetchEvents?: () => void; + userRole?: string; + key: string; + id: string; + eventLocation: string; + eventName: string; + eventDescription: string; + startDate: string; + endDate: string; + startTime: string | null; + endTime: string | null; + allDay: boolean; + recurring: boolean; + recurrenceRule: InterfaceRecurrenceRule | null; + isRecurringEventException: boolean; + isPublic: boolean; + isRegisterable: boolean; + registrants?: { + _id: string; + }[]; + creator?: { + firstName: string; + lastName: string; + _id: string; + }; +} + +function eventListCard(props: InterfaceEventListCardProps): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'eventListCard', + }); + const { t: tCommon } = useTranslation('common'); + + const [eventModalIsOpen, setEventModalIsOpen] = useState(false); + + const { orgId } = useParams(); + if (!orgId) { + return ; + } + + const showViewModal = (): void => { + setEventModalIsOpen(true); + }; + + const hideViewModal = (): void => { + setEventModalIsOpen(false); + }; + + return ( + <> +
    +
    +

    + {props.eventName ? <>{props.eventName} : <>Dogs Care} +

    +
    +
    + + + + ); +} +export {}; +export default eventListCard; diff --git a/src/components/EventListCard/EventListCardMocks.ts b/src/components/EventListCard/EventListCardMocks.ts new file mode 100644 index 0000000000..e5f7ea3227 --- /dev/null +++ b/src/components/EventListCard/EventListCardMocks.ts @@ -0,0 +1,201 @@ +import { + DELETE_EVENT_MUTATION, + REGISTER_EVENT, + UPDATE_EVENT_MUTATION, +} from 'GraphQl/Mutations/mutations'; + +export const MOCKS = [ + { + request: { + query: DELETE_EVENT_MUTATION, + variables: { id: '1' }, + }, + result: { + data: { + removeEvent: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: DELETE_EVENT_MUTATION, + variables: { id: '1', recurringEventDeleteType: 'thisInstance' }, + }, + result: { + data: { + removeEvent: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: UPDATE_EVENT_MUTATION, + variables: { + id: '1', + title: 'Updated title', + description: 'This is a new update', + isPublic: false, + recurring: false, + isRegisterable: true, + allDay: true, + startDate: '2022-03-18', + endDate: '2022-03-20', + location: 'New Delhi', + }, + }, + result: { + data: { + updateEvent: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: UPDATE_EVENT_MUTATION, + variables: { + id: '1', + title: 'Updated title', + description: 'This is a new update', + isPublic: false, + recurring: false, + isRegisterable: true, + allDay: false, + startDate: '2022-03-18', + endDate: '2022-03-20', + location: 'New Delhi', + startTime: '09:00:00Z', + endTime: '17:00:00Z', + }, + }, + result: { + data: { + updateEvent: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: UPDATE_EVENT_MUTATION, + variables: { + id: '1', + title: 'Updated title', + description: 'This is a new update', + isPublic: false, + recurring: true, + recurringEventUpdateType: 'thisInstance', + isRegisterable: true, + allDay: true, + startDate: '2022-03-18', + endDate: '2022-03-20', + location: 'New Delhi', + recurrenceStartDate: '2022-03-18', + recurrenceEndDate: null, + frequency: 'WEEKLY', + weekDays: ['FRIDAY'], + interval: 1, + }, + }, + result: { + data: { + updateEvent: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: UPDATE_EVENT_MUTATION, + variables: { + id: '1', + title: 'Updated title', + description: 'This is a new update', + isPublic: true, + recurring: true, + recurringEventUpdateType: 'allInstances', + isRegisterable: false, + allDay: true, + startDate: '2022-03-17', + endDate: '2022-03-17', + location: 'New Delhi', + recurrenceStartDate: '2022-03-17', + recurrenceEndDate: '2023-03-17', + frequency: 'MONTHLY', + weekDays: ['THURSDAY'], + interval: 1, + weekDayOccurenceInMonth: 3, + }, + }, + result: { + data: { + updateEvent: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: UPDATE_EVENT_MUTATION, + variables: { + id: '1', + title: 'Shelter for Cats', + description: 'This is shelter for cat event', + isPublic: true, + recurring: true, + recurringEventUpdateType: 'thisAndFollowingInstances', + isRegisterable: false, + allDay: true, + startDate: '2022-03-18', + endDate: '2022-03-20', + location: 'India', + recurrenceStartDate: '2022-03-18', + recurrenceEndDate: null, + frequency: 'DAILY', + interval: 1, + }, + }, + result: { + data: { + updateEvent: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: REGISTER_EVENT, + variables: { eventId: '1' }, + }, + result: { + data: { + registerForEvent: [ + { + _id: '123', + }, + ], + }, + }, + }, +]; + +export const ERROR_MOCKS = [ + { + request: { + query: DELETE_EVENT_MUTATION, + variables: { + id: '1', + }, + }, + error: new Error('Something went wrong'), + }, +]; diff --git a/src/components/EventListCard/EventListCardModals.tsx b/src/components/EventListCard/EventListCardModals.tsx new file mode 100644 index 0000000000..51612f45e5 --- /dev/null +++ b/src/components/EventListCard/EventListCardModals.tsx @@ -0,0 +1,815 @@ +import React, { useEffect, useState } from 'react'; +import { Button, Form, Modal, Popover } from 'react-bootstrap'; +import styles from './EventListCard.module.css'; +import { DatePicker, TimePicker } from '@mui/x-date-pickers'; +import dayjs from 'dayjs'; +import type { Dayjs } from 'dayjs'; +import type { InterfaceEventListCardProps } from './EventListCard'; +import { + type InterfaceRecurrenceRuleState, + type RecurringEventMutationType, + Days, + Frequency, + allInstances, + getRecurrenceRuleText, + getWeekDayOccurenceInMonth, + recurringEventMutationOptions, + thisAndFollowingInstances, + thisInstance, + haveInstanceDatesChanged, + hasRecurrenceRuleChanged, +} from 'utils/recurrenceUtils'; +import useLocalStorage from 'utils/useLocalstorage'; +import RecurrenceOptions from 'components/RecurrenceOptions/RecurrenceOptions'; +import { useNavigate, useParams } from 'react-router-dom'; +import { + DELETE_EVENT_MUTATION, + REGISTER_EVENT, + UPDATE_EVENT_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import { useMutation } from '@apollo/client'; +import { toast } from 'react-toastify'; +import { errorHandler } from 'utils/errorHandler'; + +enum Role { + USER = 'USER', + SUPERADMIN = 'SUPERADMIN', + ADMIN = 'ADMIN', +} + +const timeToDayJs = (time: string): Dayjs => { + const dateTimeString = dayjs().format('YYYY-MM-DD') + ' ' + time; + return dayjs(dateTimeString, { format: 'YYYY-MM-DD HH:mm:ss' }); +}; + +interface InterfaceEventListCardModalProps { + eventListCardProps: InterfaceEventListCardProps; + eventModalIsOpen: boolean; + hideViewModal: () => void; + t: (key: string) => string; + tCommon: (key: string) => string; +} + +function EventListCardModals({ + eventListCardProps, + eventModalIsOpen, + hideViewModal, + t, + tCommon, +}: InterfaceEventListCardModalProps): JSX.Element { + const { refetchEvents } = eventListCardProps; + + const { getItem } = useLocalStorage(); + const userId = getItem('userId'); + + const { orgId } = useParams(); + const navigate = useNavigate(); + + const [alldaychecked, setAllDayChecked] = useState(eventListCardProps.allDay); + const [recurringchecked, setRecurringChecked] = useState( + eventListCardProps.recurring, + ); + const [publicchecked, setPublicChecked] = useState( + eventListCardProps.isPublic, + ); + const [registrablechecked, setRegistrableChecked] = useState( + eventListCardProps.isRegisterable, + ); + const [eventDeleteModalIsOpen, setEventDeleteModalIsOpen] = useState(false); + const [recurringEventUpdateModalIsOpen, setRecurringEventUpdateModalIsOpen] = + useState(false); + const [eventStartDate, setEventStartDate] = useState( + new Date(eventListCardProps.startDate), + ); + const [eventEndDate, setEventEndDate] = useState( + new Date(eventListCardProps.endDate), + ); + + const [recurrenceRuleState, setRecurrenceRuleState] = + useState({ + recurrenceStartDate: eventStartDate, + recurrenceEndDate: null, + frequency: Frequency.WEEKLY, + weekDays: [Days[eventStartDate.getDay()]], + interval: 1, + count: undefined, + weekDayOccurenceInMonth: undefined, + }); + + const { + recurrenceStartDate, + recurrenceEndDate, + frequency, + weekDays, + interval, + count, + weekDayOccurenceInMonth, + } = recurrenceRuleState; + + const recurrenceRuleText = getRecurrenceRuleText(recurrenceRuleState); + + const [formState, setFormState] = useState({ + title: eventListCardProps.eventName, + eventdescrip: eventListCardProps.eventDescription, + location: eventListCardProps.eventLocation, + startTime: eventListCardProps.startTime?.split('.')[0] || '08:00:00', + endTime: eventListCardProps.endTime?.split('.')[0] || '08:00:00', + }); + + const [recurringEventDeleteType, setRecurringEventDeleteType] = + useState(thisInstance); + + const [recurringEventUpdateType, setRecurringEventUpdateType] = + useState(thisInstance); + + const [recurringEventUpdateOptions, setRecurringEventUpdateOptions] = + useState([ + thisInstance, + thisAndFollowingInstances, + allInstances, + ]); + + const [ + shouldShowRecurringEventUpdateOptions, + setShouldShowRecurringEventUpdateOptions, + ] = useState(true); + + useEffect(() => { + if (eventModalIsOpen) { + if (eventListCardProps.recurrenceRule) { + // get the recurrence rule + const { recurrenceRule } = eventListCardProps; + + // set the recurrence rule state + setRecurrenceRuleState({ + recurrenceStartDate: new Date(recurrenceRule.recurrenceStartDate), + recurrenceEndDate: recurrenceRule.recurrenceEndDate + ? new Date(recurrenceRule.recurrenceEndDate) + : null, + frequency: recurrenceRule.frequency, + weekDays: recurrenceRule.weekDays, + interval: recurrenceRule.interval, + count: recurrenceRule.count ?? undefined, + weekDayOccurenceInMonth: + recurrenceRule.weekDayOccurenceInMonth ?? undefined, + }); + } + } + }, [eventModalIsOpen]); + + // a state to specify whether the recurrence rule has changed + const [recurrenceRuleChanged, setRecurrenceRuleChanged] = useState(false); + + // a state to specify whether the instance's startDate or endDate has changed + const [instanceDatesChanged, setInstanceDatesChanged] = useState(false); + + // the `recurrenceRuleChanged` & `instanceDatesChanged` are required, + // because we will provide recurring event update options based on them, i.e.: + // - if the `instanceDatesChanged` is true, we'll not provide the option to update "allInstances" + // - if the `recurrenceRuleChanged` is true, we'll not provide the option to update "thisInstance" + // - if both are true, we'll only provide the option to update "thisAndFollowingInstances" + // updating recurring events is not very straightforward, + // find more info on the approach in this doc https://docs.talawa.io/docs/functionalities/recurring-events + + useEffect(() => { + setInstanceDatesChanged( + haveInstanceDatesChanged( + eventListCardProps.startDate, + eventListCardProps.endDate, + dayjs(eventStartDate).format('YYYY-MM-DD'), // convert to date string + dayjs(eventEndDate).format('YYYY-MM-DD'), // convert to date string + ), + ); + setRecurrenceRuleChanged( + hasRecurrenceRuleChanged( + eventListCardProps.recurrenceRule, + recurrenceRuleState, + ), + ); + }, [eventStartDate, eventEndDate, recurrenceRuleState]); + + useEffect(() => { + if (instanceDatesChanged) { + setRecurringEventUpdateType(thisInstance); + setRecurringEventUpdateOptions([thisInstance, thisAndFollowingInstances]); + setShouldShowRecurringEventUpdateOptions(true); + } + + if (recurrenceRuleChanged) { + setRecurringEventUpdateType(thisAndFollowingInstances); + setRecurringEventUpdateOptions([thisAndFollowingInstances, allInstances]); + setShouldShowRecurringEventUpdateOptions(true); + } + + if (recurrenceRuleChanged && instanceDatesChanged) { + setRecurringEventUpdateType(thisAndFollowingInstances); + setShouldShowRecurringEventUpdateOptions(false); + } + + if (!recurrenceRuleChanged && !instanceDatesChanged) { + setRecurringEventUpdateType(thisInstance); + setRecurringEventUpdateOptions([ + thisInstance, + thisAndFollowingInstances, + allInstances, + ]); + setShouldShowRecurringEventUpdateOptions(true); + } + }, [recurrenceRuleChanged, instanceDatesChanged]); + + const [updateEvent] = useMutation(UPDATE_EVENT_MUTATION); + + const updateEventHandler = async (): Promise => { + try { + const { data } = await updateEvent({ + variables: { + id: eventListCardProps.id, + title: formState.title, + description: formState.eventdescrip, + isPublic: publicchecked, + recurring: recurringchecked, + recurringEventUpdateType: recurringchecked + ? recurringEventUpdateType + : undefined, + isRegisterable: registrablechecked, + allDay: alldaychecked, + startDate: dayjs(eventStartDate).format('YYYY-MM-DD'), + endDate: dayjs(eventEndDate).format('YYYY-MM-DD'), + location: formState.location, + startTime: !alldaychecked ? formState.startTime + 'Z' : undefined, + endTime: !alldaychecked ? formState.endTime + 'Z' : undefined, + recurrenceStartDate: recurringchecked + ? recurringEventUpdateType === thisAndFollowingInstances && + (instanceDatesChanged || recurrenceRuleChanged) + ? dayjs(eventStartDate).format('YYYY-MM-DD') + : dayjs(recurrenceStartDate).format('YYYY-MM-DD') + : undefined, + recurrenceEndDate: recurringchecked + ? recurrenceEndDate + ? dayjs(recurrenceEndDate).format('YYYY-MM-DD') + : null + : undefined, + frequency: recurringchecked ? frequency : undefined, + weekDays: + recurringchecked && + (frequency === Frequency.WEEKLY || + (frequency === Frequency.MONTHLY && weekDayOccurenceInMonth)) + ? weekDays + : undefined, + interval: recurringchecked ? interval : undefined, + count: recurringchecked ? count : undefined, + weekDayOccurenceInMonth: recurringchecked + ? weekDayOccurenceInMonth + : undefined, + }, + }); + + if (data) { + toast.success(t('eventUpdated')); + setRecurringEventUpdateModalIsOpen(false); + hideViewModal(); + if (refetchEvents) { + refetchEvents(); + } + } + } catch (error: unknown) { + /* istanbul ignore next */ + errorHandler(t, error); + } + }; + + const handleEventUpdate = async (): Promise => { + if (!eventListCardProps.recurring) { + await updateEventHandler(); + } else { + if (shouldShowRecurringEventUpdateOptions) { + setRecurringEventUpdateModalIsOpen(true); + } else { + await updateEventHandler(); + } + } + }; + + const [deleteEvent] = useMutation(DELETE_EVENT_MUTATION); + + const deleteEventHandler = async (): Promise => { + try { + const { data } = await deleteEvent({ + variables: { + id: eventListCardProps.id, + recurringEventDeleteType: eventListCardProps.recurring + ? recurringEventDeleteType + : undefined, + }, + }); + + if (data) { + toast.success(t('eventDeleted')); + setEventDeleteModalIsOpen(false); + hideViewModal(); + if (refetchEvents) { + refetchEvents(); + } + } + } catch (error: unknown) { + errorHandler(t, error); + } + }; + + const toggleDeleteModal = (): void => { + setEventDeleteModalIsOpen(!eventDeleteModalIsOpen); + }; + + const isInitiallyRegistered = eventListCardProps?.registrants?.some( + (registrant) => registrant._id === userId, + ); + const [registerEventMutation] = useMutation(REGISTER_EVENT); + const [isRegistered, setIsRegistered] = useState(isInitiallyRegistered); + + const registerEventHandler = async (): Promise => { + if (!isRegistered) { + try { + const { data } = await registerEventMutation({ + variables: { + eventId: eventListCardProps.id, + }, + }); + + if (data) { + toast.success( + `Successfully registered for ${eventListCardProps.eventName}`, + ); + setIsRegistered(true); + hideViewModal(); + } + } catch (error: unknown) { + /* istanbul ignore next */ + errorHandler(t, error); + } + } + }; + + const toggleRecurringEventUpdateModal = (): void => { + setRecurringEventUpdateModalIsOpen(!recurringEventUpdateModalIsOpen); + }; + + const openEventDashboard = (): void => { + const userPath = eventListCardProps.userRole === Role.USER ? 'user/' : ''; + console.log(`/${userPath}event/${orgId}/${eventListCardProps.id}`); + navigate(`/${userPath}event/${orgId}/${eventListCardProps.id}`); + }; + + const popover = ( + + {recurrenceRuleText} + + ); + + return ( + <> + {/* preview modal */} + + +

    {t('eventDetails')}

    + +
    + +
    +

    {t('eventTitle')}

    + 100 + ? formState.title.substring(0, 100) + '...' + : formState.title + } + onChange={(e): void => { + setFormState({ + ...formState, + title: e.target.value, + }); + }} + disabled={ + !(eventListCardProps.creator?._id === userId) && + eventListCardProps.userRole === Role.USER + } + /> +

    {tCommon('description')}

    + 256 + ? formState.eventdescrip.substring(0, 256) + '...' + : formState.eventdescrip + } + onChange={(e): void => { + setFormState({ + ...formState, + eventdescrip: e.target.value, + }); + }} + disabled={ + !(eventListCardProps.creator?._id === userId) && + eventListCardProps.userRole === Role.USER + } + /> +

    {tCommon('location')}

    + { + setFormState({ + ...formState, + location: e.target.value, + }); + }} + disabled={ + !(eventListCardProps.creator?._id === userId) && + eventListCardProps.userRole === Role.USER + } + /> +
    +
    + { + if (date) { + setEventStartDate(date?.toDate()); + setEventEndDate( + eventEndDate < date?.toDate() + ? date?.toDate() + : eventEndDate, + ); + if (!eventListCardProps.recurring) { + setRecurrenceRuleState({ + ...recurrenceRuleState, + recurrenceStartDate: date?.toDate(), + weekDays: [Days[date?.toDate().getDay()]], + weekDayOccurenceInMonth: weekDayOccurenceInMonth + ? /* istanbul ignore next */ getWeekDayOccurenceInMonth( + date?.toDate(), + ) + : undefined, + }); + } + } + }} + /> +
    +
    + { + if (date) { + setEventEndDate(date?.toDate()); + } + }} + minDate={dayjs(eventStartDate)} + /> +
    +
    + {!alldaychecked && ( +
    +
    + { + if (time) { + setFormState({ + ...formState, + startTime: time?.format('HH:mm:ss'), + endTime: + timeToDayJs(formState.endTime) < time + ? time?.format('HH:mm:ss') + : /* istanbul ignore next */ + formState.endTime, + }); + } + }} + disabled={alldaychecked} + /> +
    +
    + { + if (time) { + setFormState({ + ...formState, + endTime: time?.format('HH:mm:ss'), + }); + } + }} + minTime={timeToDayJs(formState.startTime)} + disabled={alldaychecked} + /> +
    +
    + )} +
    +
    +
    + + { + setAllDayChecked(!alldaychecked); + }} + disabled={ + !(eventListCardProps.creator?._id === userId) && + eventListCardProps.userRole === Role.USER + } + /> +
    +
    + + { + setRecurringChecked(!recurringchecked); + }} + disabled={ + !(eventListCardProps.creator?._id === userId) && + eventListCardProps.userRole === Role.USER + } + /> +
    +
    +
    +
    + + { + setPublicChecked(!publicchecked); + }} + disabled={ + !(eventListCardProps.creator?._id === userId) && + eventListCardProps.userRole === Role.USER + } + /> +
    +
    + + { + setRegistrableChecked(!registrablechecked); + }} + disabled={ + !(eventListCardProps.creator?._id === userId) && + eventListCardProps.userRole === Role.USER + } + /> +
    +
    +
    + + {/* Recurrence Options */} + {recurringchecked && ( + + )} + +
    + + {(eventListCardProps.userRole !== Role.USER || + eventListCardProps.creator?._id === userId) && ( + + )} + {(eventListCardProps.userRole !== Role.USER || + eventListCardProps.creator?._id === userId) && ( + + )} + {(eventListCardProps.userRole !== Role.USER || + eventListCardProps.creator?._id === userId) && ( + + )} + {eventListCardProps.userRole === Role.USER && + !(eventListCardProps.creator?._id === userId) && + (isRegistered ? ( + + ) : ( + + ))} + +
    + + {/* recurring event update options modal */} + + + + {t('editEvent')} + + + +
    + {recurringEventUpdateOptions.map((option, index) => ( +
    + + setRecurringEventUpdateType( + e.target.value as RecurringEventMutationType, + ) + } + defaultChecked={option === recurringEventUpdateType} + data-testid={`update-${option}`} + /> +
    + ))} +
    +
    + + + + +
    + + {/* delete modal */} + + + + {t('deleteEvent')} + + + + {!eventListCardProps.recurring && t('deleteEventMsg')} + {eventListCardProps.recurring && ( + <> +
    + {recurringEventMutationOptions.map((option, index) => ( +
    + + setRecurringEventDeleteType( + e.target.value as RecurringEventMutationType, + ) + } + defaultChecked={option === recurringEventDeleteType} + data-testid={`delete-${option}`} + /> +
    + ))} +
    + + )} +
    + + + + +
    + + ); +} + +export default EventListCardModals; diff --git a/src/components/EventListCard/EventListCardProps.ts b/src/components/EventListCard/EventListCardProps.ts new file mode 100644 index 0000000000..9aef474254 --- /dev/null +++ b/src/components/EventListCard/EventListCardProps.ts @@ -0,0 +1,194 @@ +import { Frequency, WeekDays } from 'utils/recurrenceUtils'; +import type { InterfaceEventListCardProps } from './EventListCard'; + +export const props: InterfaceEventListCardProps[] = [ + { + key: '', + id: '', + eventLocation: '', + eventName: '', + eventDescription: '', + startDate: '', + endDate: '', + startTime: '', + endTime: '', + allDay: false, + recurring: false, + recurrenceRule: null, + isRecurringEventException: false, + isPublic: false, + isRegisterable: false, + refetchEvents: (): void => { + /* refetch function */ + }, + }, + { + key: '123', + id: '1', + eventLocation: 'India', + eventName: 'Shelter for Dogs', + eventDescription: 'This is shelter for dogs event', + startDate: '2022-03-19', + endDate: '2022-03-26', + startTime: '02:00', + endTime: '06:00', + allDay: false, + recurring: false, + recurrenceRule: null, + isRecurringEventException: false, + isPublic: true, + isRegisterable: false, + refetchEvents: (): void => { + /* refetch function */ + }, + }, + { + userRole: 'USER', + key: '123', + id: '1', + eventLocation: 'India', + eventName: 'Shelter for Dogs', + eventDescription: 'This is shelter for dogs event', + startDate: '2022-03-19', + endDate: '2022-03-26', + startTime: '02:00', + endTime: '06:00', + allDay: true, + recurring: false, + recurrenceRule: null, + isRecurringEventException: false, + isPublic: true, + isRegisterable: false, + creator: { + firstName: 'Joe', + lastName: 'David', + _id: '123', + }, + registrants: [ + { + _id: '234', + }, + ], + refetchEvents: (): void => { + /* refetch function */ + }, + }, + { + userRole: 'USER', + key: '123', + id: '1', + eventLocation: 'India', + eventName: 'Shelter for Dogs', + eventDescription: 'This is shelter for dogs event', + startDate: '2022-03-19', + endDate: '2022-03-26', + startTime: '02:00', + endTime: '06:00', + allDay: true, + recurring: false, + recurrenceRule: null, + isRecurringEventException: false, + isPublic: true, + isRegisterable: false, + creator: { + firstName: 'Joe', + lastName: 'David', + _id: '123', + }, + registrants: [ + { + _id: '456', + }, + ], + refetchEvents: (): void => { + /* refetch function */ + }, + }, + { + userRole: 'ADMIN', + key: '123', + id: '1', + eventLocation: 'India', + eventName: 'Shelter for Cats', + eventDescription: 'This is shelter for cat event', + startDate: '2022-03-19', + endDate: '2022-03-19', + startTime: '2:00', + endTime: '6:00', + allDay: false, + recurring: true, + recurrenceRule: { + recurrenceStartDate: '2022-03-19', + recurrenceEndDate: '2022-03-26', + frequency: Frequency.WEEKLY, + weekDays: [WeekDays.SATURDAY], + interval: 1, + count: null, + weekDayOccurenceInMonth: null, + }, + isRecurringEventException: false, + isPublic: true, + isRegisterable: false, + refetchEvents: (): void => { + /* refetch function */ + }, + }, + { + userRole: 'ADMIN', + key: '123', + id: '1', + eventLocation: 'India', + eventName: 'Shelter for Cats', + eventDescription: 'This is shelter for cat event', + startDate: '2022-03-17', + endDate: '2022-03-17', + startTime: null, + endTime: null, + allDay: true, + recurring: true, + recurrenceRule: { + recurrenceStartDate: '2022-03-17', + recurrenceEndDate: null, + frequency: Frequency.MONTHLY, + weekDays: [WeekDays.THURSDAY], + interval: 1, + count: null, + weekDayOccurenceInMonth: 3, + }, + isRecurringEventException: false, + isPublic: true, + isRegisterable: false, + refetchEvents: (): void => { + /* refetch function */ + }, + }, + { + userRole: 'ADMIN', + key: '123', + id: '1', + eventLocation: 'India', + eventName: 'Shelter for Cats', + eventDescription: 'This is shelter for cat event', + startDate: '2022-03-17', + endDate: '2022-03-17', + startTime: null, + endTime: null, + allDay: true, + recurring: true, + recurrenceRule: { + recurrenceStartDate: '2022-03-17', + recurrenceEndDate: '2023-03-17', + frequency: Frequency.MONTHLY, + weekDays: [WeekDays.THURSDAY], + interval: 1, + count: null, + weekDayOccurenceInMonth: 3, + }, + isRecurringEventException: false, + isPublic: true, + isRegisterable: false, + refetchEvents: (): void => { + /* refetch function */ + }, + }, +]; diff --git a/src/components/EventManagement/Dashboard/EventDashboard.mocks.ts b/src/components/EventManagement/Dashboard/EventDashboard.mocks.ts new file mode 100644 index 0000000000..5aeb20b205 --- /dev/null +++ b/src/components/EventManagement/Dashboard/EventDashboard.mocks.ts @@ -0,0 +1,65 @@ +import { EVENT_DETAILS } from 'GraphQl/Queries/Queries'; + +// Mock 1 +export const MOCKS_WITH_TIME = [ + { + request: { + query: EVENT_DETAILS, + variables: { + id: 'event123', + }, + }, + result: { + data: { + event: { + _id: 'event123', + title: 'Event Title', + description: 'Event Description', + startDate: '1/1/23', + endDate: '16/2/23', + startTime: '08:00:00', + endTime: '09:00:00', + allDay: false, + location: 'India', + organization: { + _id: 'org1', + members: [{ _id: 'user1', firstName: 'John', lastName: 'Doe' }], + }, + attendees: [{ _id: 'user1' }], + }, + }, + }, + }, +]; + +// Mock 2 +export const MOCKS_WITHOUT_TIME = [ + { + request: { + query: EVENT_DETAILS, + variables: { + id: 'event123', + }, + }, + result: { + data: { + event: { + _id: 'event123', + title: 'Event Title', + description: 'Event Description', + startDate: '1/1/23', + endDate: '2/2/23', + startTime: null, + endTime: null, + allDay: false, + location: 'India', + organization: { + _id: 'org1', + members: [{ _id: 'user1', firstName: 'John', lastName: 'Doe' }], + }, + attendees: [{ _id: 'user1' }], + }, + }, + }, + }, +]; diff --git a/src/components/EventManagement/Dashboard/EventDashboard.module.css b/src/components/EventManagement/Dashboard/EventDashboard.module.css new file mode 100644 index 0000000000..b7a29e0011 --- /dev/null +++ b/src/components/EventManagement/Dashboard/EventDashboard.module.css @@ -0,0 +1,76 @@ +.eventContainer { + display: flex; + align-items: center; +} + +.eventDetailsBox { + position: relative; + margin-left: 50px; + height: 90%; + width: 45%; + box-sizing: border-box; + background: #ffffff; + border: 1px solid #dddddd; + border-radius: 8px; + margin-bottom: 0; +} + +.eventDetailsBox::before { + content: ''; + position: absolute; + top: 0; + height: 100%; + width: 6px; + background-color: #31bb6b; + border-radius: 8px; +} + +.time { + display: flex; + justify-content: space-between; + padding: 15px; + padding-bottom: 0px; +} + +.startTime, +.endTime { + display: flex; + font-size: 20px; +} + +.to { + padding-right: 10px; +} + +.startDate, +.endDate { + color: #808080; + font-size: 14px; +} + +.titlename { + font-weight: 600; + font-size: 20px; + padding: 15px; + padding-bottom: 0px; + width: 100%; +} + +.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; +} diff --git a/src/components/EventManagement/Dashboard/EventDashboard.test.tsx b/src/components/EventManagement/Dashboard/EventDashboard.test.tsx new file mode 100644 index 0000000000..24a4ba207a --- /dev/null +++ b/src/components/EventManagement/Dashboard/EventDashboard.test.tsx @@ -0,0 +1,83 @@ +import React from 'react'; +import type { RenderResult } from '@testing-library/react'; +import { render, act } from '@testing-library/react'; +import EventDashboard from './EventDashboard'; +import { BrowserRouter } from 'react-router-dom'; +import { ToastContainer } from 'react-toastify'; +import { MockedProvider } from '@apollo/react-testing'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { I18nextProvider } from 'react-i18next'; +import i18nForTest from 'utils/i18nForTest'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import type { ApolloLink, DefaultOptions } from '@apollo/client'; + +import { MOCKS_WITHOUT_TIME, MOCKS_WITH_TIME } from './EventDashboard.mocks'; +import { StaticMockLink } from 'utils/StaticMockLink'; + +const mockWithTime = new StaticMockLink(MOCKS_WITH_TIME, true); +const mockWithoutTime = new StaticMockLink(MOCKS_WITHOUT_TIME, true); + +// We want to disable all forms of caching so that we do not need to define a custom merge function in testing for the network requests +const defaultOptions: DefaultOptions = { + watchQuery: { + fetchPolicy: 'no-cache', + errorPolicy: 'ignore', + }, + query: { + fetchPolicy: 'no-cache', + errorPolicy: 'all', + }, +}; + +async function wait(ms = 500): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const mockID = 'event123'; +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ eventId: mockID }), +})); + +const renderEventDashboard = (mockLink: ApolloLink): RenderResult => { + return render( + + + + + + + + + + , + ); +}; + +describe('Testing Event Dashboard Screen', () => { + test('The page should display event details correctly and also show the time if provided', async () => { + const { queryByText, queryAllByText } = renderEventDashboard(mockWithTime); + + await wait(); + + expect(queryAllByText('Event Title').length).toBe(1); + expect(queryAllByText('Event Description').length).toBe(1); + expect(queryByText('India')).toBeInTheDocument(); + + await wait(); + }); + + test('The page should display event details correctly and should not show the time if it is null', async () => { + const { queryAllByText } = renderEventDashboard(mockWithoutTime); + await wait(); + expect(queryAllByText('Event Title').length).toBe(1); + }); +}); diff --git a/src/components/EventManagement/Dashboard/EventDashboard.tsx b/src/components/EventManagement/Dashboard/EventDashboard.tsx new file mode 100644 index 0000000000..84b0493198 --- /dev/null +++ b/src/components/EventManagement/Dashboard/EventDashboard.tsx @@ -0,0 +1,108 @@ +import React from 'react'; +import { Col, Row } from 'react-bootstrap'; +import styles from './EventDashboard.module.css'; +import { useTranslation } from 'react-i18next'; +import { EVENT_DETAILS } from 'GraphQl/Queries/Queries'; +import { useQuery } from '@apollo/client'; +import Loader from 'components/Loader/Loader'; + +const EventDashboard = (props: { eventId: string }): JSX.Element => { + const { eventId } = props; + const { t } = useTranslation('translation', { + keyPrefix: 'eventManagement', + }); + + const { data: eventData, loading: eventInfoLoading } = useQuery( + EVENT_DETAILS, + { + variables: { id: eventId }, + }, + ); + + if (eventInfoLoading) { + return ; + } + + function formatTime(timeString: string): string { + const [hours, minutes] = timeString.split(':').slice(0, 2); + return `${hours}:${minutes}`; + } + + function formatDate(dateString: string): string { + const date = new Date(dateString); + const day = date.getDate(); + const monthIndex = date.getMonth(); + const year = date.getFullYear(); + + const suffixes = ['th', 'st', 'nd', 'rd']; + const suffix = suffixes[day % 10] || suffixes[0]; + + const monthNames = [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec', + ]; + + const formattedDate = `${day}${suffix} ${monthNames[monthIndex]} ${year}`; + return formattedDate; + } + return ( +
    + + +
    +
    +
    +

    + + {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)}{' '} + +

    +
    +

    {eventData.event.title}

    +

    + {eventData.event.description} +

    +

    + Location: {eventData.event.location} +

    +

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

    +
    +
    +
    + +
    +
    + ); +}; + +export default EventDashboard; diff --git a/src/components/EventManagement/EventActionItems/EventActionItems.module.css b/src/components/EventManagement/EventActionItems/EventActionItems.module.css new file mode 100644 index 0000000000..120177d155 --- /dev/null +++ b/src/components/EventManagement/EventActionItems/EventActionItems.module.css @@ -0,0 +1,206 @@ +@media screen and (max-width: 575.5px) { + .mainpageright { + width: 98%; + } +} +.actionItemModal { + max-width: 80vw; + margin-top: 2vh; + margin-left: 13vw; +} +.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; +} +.datagrid { + overflow: auto; + border-radius: 10px; +} +.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 { + color: var(--bs-black); + font-size: var(--bs-body-font-size); +} +.addButton { + width: 7em; + position: absolute; + right: 1rem; + top: 1rem; +} + +.createModal { + margin-top: 20vh; + margin-left: 13vw; + max-width: 80vw; +} + +.icon { + transform: scale(1.5); + color: var(--bs-danger); + margin-bottom: 1rem; +} + +.message { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.titlemodal { + color: var(--bs-gray-600); + font-weight: 600; + font-size: 20px; + margin-bottom: 20px; + padding-bottom: 5px; + border-bottom: 3px solid var(--bs-primary); + width: 65%; +} + +.editDelBtns { + margin-top: 15px; + 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%; +} + +.greenregbtn { + margin-left: 93%; +} + +.datatable { + margin-top: 5rem; +} + +.datediv { + display: flex; + flex-direction: row; +} +.datebox { + width: 90%; + border-radius: 7px; + outline: none; + box-shadow: none; +} +.actionItemsOptionsButton { + width: 24px; + height: 24px; +} + +@-webkit-keyframes load8 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@keyframes load8 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} diff --git a/src/components/EventManagement/EventActionItems/EventActionItems.test.tsx b/src/components/EventManagement/EventActionItems/EventActionItems.test.tsx new file mode 100644 index 0000000000..9da0b5247a --- /dev/null +++ b/src/components/EventManagement/EventActionItems/EventActionItems.test.tsx @@ -0,0 +1,1179 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { + act, + fireEvent, + render, + screen, + waitFor, + waitForElementToBeRemoved, +} from '@testing-library/react'; +import 'jest-localstorage-mock'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import userEvent from '@testing-library/user-event'; +import { I18nextProvider } from 'react-i18next'; +import EventActionItems from './EventActionItems'; +import { store } from 'state/store'; +import 'jest-location-mock'; +import { toast } from 'react-toastify'; +import i18nForTest from 'utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { + CREATE_ACTION_ITEM_MUTATION, + UPDATE_ACTION_ITEM_MUTATION, + DELETE_ACTION_ITEM_MUTATION, +} from 'GraphQl/Mutations/ActionItemMutations'; +import { + ACTION_ITEM_CATEGORY_LIST, + MEMBERS_LIST, +} from 'GraphQl/Queries/Queries'; +import { ACTION_ITEM_LIST_BY_EVENTS } from 'GraphQl/Queries/ActionItemQueries'; + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +const MOCKS = [ + { + request: { + query: CREATE_ACTION_ITEM_MUTATION, + variables: { + assigneeId: '658930fd2caa9d8d6908745c', + actionItemCategoryId: '65f069a53b63ad266db32b3f', + eventId: '123', + preCompletionNotes: 'task to be done with high priority', + dueDate: '2024-04-05', + }, + }, + result: { + data: { + createActionItem: { + _id: 'newly_created_action_item_id', + }, + }, + }, + }, + { + request: { + query: UPDATE_ACTION_ITEM_MUTATION, + variables: { + actionItemId: '_6613ef741677gygwuyu', + assigneeId: '658930fd2caa9d8d690sfhgush', + preCompletionNotes: 'pre completion notes edited', + postCompletionNotes: 'Post Completion Notes', + dueDate: '2024-02-14', + completionDate: '2024-02-21', + isCompleted: false, + }, + }, + result: { + data: { + updateActionItem: { + _id: '_6613ef741677gygwuyu', + }, + }, + }, + }, + { + request: { + query: UPDATE_ACTION_ITEM_MUTATION, + variables: { + actionItemId: '_6613ef741677gygwuyu', + assigneeId: '658930fd2caa9d8d6908745c', + preCompletionNotes: 'Pre Completion Notes', + postCompletionNotes: 'this action item has been completed successfully', + dueDate: '2024-02-21', + completionDate: '2024-02-21', + isCompleted: true, + }, + }, + result: { + data: { + updateActionItem: { + _id: '_6613ef741677gygwuyu', + }, + }, + }, + }, + { + request: { + query: UPDATE_ACTION_ITEM_MUTATION, + variables: { + actionItemId: 'actionItem2', + assigneeId: 'user1', + preCompletionNotes: 'this action item has been made active again', + postCompletionNotes: 'Post Completion Notes', + dueDate: '2024-02-21', + completionDate: '2024-02-21', + isCompleted: false, + }, + }, + result: { + data: { + updateActionItem: { + _id: '_6613ef741677gygwuyu', + }, + }, + }, + }, + { + request: { + query: DELETE_ACTION_ITEM_MUTATION, + variables: { + actionItemId: '_6613ef741677gygwuyu', + }, + }, + result: { + data: { + removeActionItem: { + _id: '_6613ef741677gygwuyu', + __typename: 'ActionItem', + }, + }, + }, + }, + { + request: { + query: ACTION_ITEM_CATEGORY_LIST, + variables: { + organizationId: '111', + }, + }, + result: { + data: { + actionItemCategoriesByOrganization: [ + { + _id: '65f069a53b63ad266db32b3f', + name: 'Default', + isDisabled: false, + __typename: 'ActionItemCategory', + }, + ], + }, + }, + }, + { + request: { + query: MEMBERS_LIST, + variables: { + id: '111', + }, + }, + result: { + data: { + organizations: [ + { + _id: '111', + members: [ + { + createdAt: '2023-04-13', + email: 'testuser4@example.com', + firstName: 'Teresa', + image: null, + lastName: 'Bradley', + organizationsBlockedBy: [], + __typename: 'User', + _id: '658930fd2caa9d8d6908745c', + }, + { + createdAt: '2024-04-13', + email: 'testuser2@example.com', + firstName: 'Anna', + image: null, + lastName: 'Bradley', + organizationsBlockedBy: [], + __typename: 'User', + _id: '658930fd2caa9d8d690sfhgush', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: ACTION_ITEM_LIST_BY_EVENTS, + variables: { + eventId: '123', + }, + }, + result: { + data: { + actionItemsByEvent: [ + { + _id: '_6613ef741677gygwuyu', + actionItemCategory: { + __typename: 'ActionItemCategory', + _id: '65f069a53b63ad266db32b3j', + name: 'Default', + }, + assignee: { + __typename: 'User', + _id: '658930fd2caa9d8d6908745c', + firstName: 'Burton', + lastName: 'Sanders', + }, + assigner: { + __typename: 'User', + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + assignmentDate: new Date('2024-02-14'), + dueDate: new Date('2024-02-21'), + completionDate: new Date('2024-02-21'), + creator: { + __typename: 'User', + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + event: { + __typename: 'Event', + _id: '123', + title: 'Adult Painting Lessons', + }, + isCompleted: false, + postCompletionNotes: 'Post Completion Notes', + preCompletionNotes: 'Pre Completion Notes', + }, + { + _id: 'actionItem2', + assignee: { + _id: '658930fd2caa9d8d6908745c', + firstName: 'Harve', + lastName: 'Lance', + }, + actionItemCategory: { + _id: 'actionItemCategory1', + name: 'ActionItemCategory 1', + }, + preCompletionNotes: + 'Long Pre Completion Notes Text that exceeds 25 characters', + postCompletionNotes: + 'Long Post Completion Notes Text that exceeds 25 characters', + assignmentDate: new Date('2024-02-14'), + dueDate: new Date('2024-02-21'), + completionDate: new Date('2024-02-21'), + isCompleted: true, + assigner: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + event: { + _id: 'event1', + title: 'event 1', + }, + creator: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + { + _id: 'actionItem3', + assignee: { + _id: '658930fd2caa9d8d6908745c', + firstName: 'Harve', + lastName: 'Lance', + }, + actionItemCategory: { + _id: 'actionItemCategory1', + name: 'ActionItemCategory 1', + }, + preCompletionNotes: 'Pre Completion Text', + postCompletionNotes: 'Post Completion Text', + assignmentDate: new Date('2024-02-14'), + dueDate: new Date('2024-02-21'), + completionDate: new Date('2024-02-21'), + isCompleted: true, + assigner: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + event: { + _id: 'event1', + title: 'event 1', + }, + creator: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + ], + }, + refetch: jest.fn(), + }, + }, +]; + +const CREATE_ACTION_ITEM_ERROR_MOCK = [ + { + request: { + query: CREATE_ACTION_ITEM_MUTATION, + variables: { + assigneeId: '658930fd2caa9d8d6908745c', + actionItemCategoryId: '65f069a53b63ad266db32b3f', + eventId: '123', + preCompletionNotes: 'task to be done with high priority', + dueDate: '2024-04-05', + }, + }, + result: { + data: { + createActionItem: { + _id: undefined, + }, + }, + }, + }, +]; + +const UPDATE_ACTION_ITEM_ERROR_MOCK = [ + { + request: { + query: ACTION_ITEM_LIST_BY_EVENTS, + variables: { + eventId: '123', + }, + }, + result: { + data: { + actionItemsByEvent: [ + { + _id: '_6613ef741677gygwuyu', + actionItemCategory: { + __typename: 'ActionItemCategory', + _id: '65f069a53b63ad266db32b3j', + name: 'Default', + }, + assignee: { + __typename: 'User', + _id: '658930fd2caa9d8d6908745c', + firstName: 'Burton', + lastName: 'Sanders', + }, + assigner: { + __typename: 'User', + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + assignmentDate: new Date('2024-02-14'), + dueDate: new Date('2024-02-21'), + completionDate: new Date('2024-02-21'), + creator: { + __typename: 'User', + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + event: { + __typename: 'Event', + _id: '123', + title: 'Adult Painting Lessons', + }, + isCompleted: false, + postCompletionNotes: 'Post Completion Note', + preCompletionNotes: 'Pre Completion Note', + }, + ], + }, + refetch: jest.fn(), + }, + }, + { + request: { + query: MEMBERS_LIST, + variables: { + id: '111', + }, + }, + result: { + data: { + organizations: [ + { + _id: '111', + members: [ + { + createdAt: '2023-04-13', + email: 'testuser4@example.com', + firstName: 'Teresa', + image: null, + lastName: 'Bradley', + organizationsBlockedBy: [], + __typename: 'User', + _id: '658930fd2caa9d8d6908745c', + }, + { + createdAt: '2024-04-13', + email: 'testuser2@example.com', + firstName: 'Anna', + image: null, + lastName: 'Bradley', + organizationsBlockedBy: [], + __typename: 'User', + _id: '658930fd2caa9d8d690sfhgush', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: DELETE_ACTION_ITEM_MUTATION, + variables: { + actionItemId: '_6613ef741677gygwuyu', + }, + }, + error: new Error('Mock Graphql Error'), + }, + { + request: { + query: UPDATE_ACTION_ITEM_MUTATION, + variables: { + actionItemId: '_6613ef741677gygwuyu', + assigneeId: '658930fd2caa9d8d690sfhgush', + preCompletionNotes: 'pre completion notes edited', + postCompletionNotes: '', + dueDate: '2024-02-14', + completionDate: '2024-02-21', + isCompleted: false, + }, + }, + error: new Error('Mock Graphql Error'), + }, +]; + +const NO_ACTION_ITEMS_ERROR_MOCK = [ + { + request: { + query: ACTION_ITEM_LIST_BY_EVENTS, + variables: { + eventId: '123', + }, + }, + result: { + data: { + actionItemsByEvent: [], + }, + refetch: jest.fn(), + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(CREATE_ACTION_ITEM_ERROR_MOCK, true); +const link3 = new StaticMockLink(UPDATE_ACTION_ITEM_ERROR_MOCK, true); +const link4 = new StaticMockLink(NO_ACTION_ITEMS_ERROR_MOCK, true); + +const translations = JSON.parse( + JSON.stringify( + i18nForTest.getDataByLanguage('en')?.translation.eventActionItems, + ), +); + +describe('Event Action Items Page', () => { + const formData = { + assignee: 'Anna Bradley', + preCompletionNotes: 'pre completion notes edited', + dueDate: '02/14/2024', + completionDate: '02/21/2024', + }; + test('Testing add new action item modal', async () => { + window.location.assign('/event/111/123'); + render( + + + + + + {} + + + + + , + ); + await wait(); + userEvent.click(screen.getByTestId('createEventActionItemBtn')); + + await wait(); + expect( + screen.getByText(translations.actionItemDetails), + ).toBeInTheDocument(); + + const categoryDropdown = screen.getByTestId('formSelectActionItemCategory'); + userEvent.selectOptions(categoryDropdown, 'Default'); + + expect(categoryDropdown).toHaveValue('65f069a53b63ad266db32b3f'); + + const assigneeDropdown = screen.getByTestId('formSelectAssignee'); + userEvent.selectOptions(assigneeDropdown, 'Teresa Bradley'); + + expect(assigneeDropdown).toHaveValue('658930fd2caa9d8d6908745c'); + + fireEvent.change( + screen.getByPlaceholderText(translations.preCompletionNotes), + { + target: { value: 'task to be done with high priority' }, + }, + ); + expect( + screen.getByPlaceholderText(translations.preCompletionNotes), + ).toHaveValue('task to be done with high priority'); + + fireEvent.change(screen.getByLabelText(translations.dueDate), { + target: { value: '04/05/2024' }, + }); + expect(screen.getByLabelText(translations.dueDate)).toHaveValue( + '04/05/2024', + ); + + userEvent.click(screen.getByTestId('createActionItemFormSubmitBtn')); + + await wait(); + + expect(toast.success).toBeCalledWith(translations.successfulCreation); + }); + + test('Display all the action items', async () => { + window.location.assign('/event/111/123'); + render( + + + + + + {} + + + + + , + ); + await wait(); + + expect(screen.getByText('#')).toBeInTheDocument(); + expect(screen.getByText(translations.assignee)).toBeInTheDocument(); + expect( + screen.getByText(translations.actionItemCategory), + ).toBeInTheDocument(); + expect( + screen.getByText(translations.preCompletionNotes), + ).toBeInTheDocument(); + expect( + screen.getByText(translations.postCompletionNotes), + ).toBeInTheDocument(); + + await wait(); + const asigneeAnchorElement = screen.getByText('Burton Sanders'); + expect(asigneeAnchorElement.tagName).toBe('A'); + expect(asigneeAnchorElement).toHaveAttribute('href', '/member/123'); + + expect(screen.getByText('Burton Sanders')).toBeInTheDocument(); + const updateButtons = screen.getAllByTestId('editActionItemModalBtn'); + const previewButtons = screen.getAllByTestId('previewActionItemModalBtn'); + const updateStatusButtons = screen.getAllByTestId( + 'actionItemStatusChangeCheckbox', + ); + expect(updateButtons[0]).toBeInTheDocument(); + expect(previewButtons[0]).toBeInTheDocument(); + expect(updateStatusButtons[0]).toBeInTheDocument(); + + // Truncate notes and long completion notes txt + expect( + screen.getAllByTestId('actionItemPreCompletionNotesOverlay')[1], + ).toHaveTextContent('Long Pre Completion Notes...'); + expect( + screen.getAllByTestId('actionItemPostCompletionNotesOverlay')[0], + ).toHaveTextContent('Long Post Completion Note...'); + expect( + screen.getAllByTestId('actionItemPostCompletionNotesOverlay')[1], + ).toHaveTextContent('Post Completion Text'); + expect( + screen.getAllByTestId('actionItemPreCompletionNotesOverlay')[2], + ).toHaveTextContent('Pre Completion Text'); + }); + + test('opens and closes the update and delete modals through the preview modal', async () => { + window.location.assign('/event/111/123'); + render( + + + + + + {} + + + + + , + ); + + await wait(); + + expect( + screen.getAllByTestId('previewActionItemModalBtn')[0], + ).toBeInTheDocument(); + userEvent.click(screen.getAllByTestId('previewActionItemModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('previewActionItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + await waitFor(() => { + expect( + screen.getByTestId('deleteActionItemPreviewModalBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteActionItemPreviewModalBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('actionItemDeleteModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('actionItemDeleteModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('actionItemDeleteModalCloseBtn'), + ); + + expect( + screen.getByTestId('editActionItemPreviewModalBtn'), + ).toBeInTheDocument(); + userEvent.click(screen.getByTestId('editActionItemPreviewModalBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('updateActionItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('updateActionItemModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('updateActionItemModalCloseBtn'), + ); + }); + test('opens and closes the action item status change modal correctly', async () => { + window.location.assign('/event/111/123'); + render( + + + + + + {} + + + + + , + ); + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('actionItemStatusChangeCheckbox')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('actionItemStatusChangeCheckbox')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('actionItemStatusChangeModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('actionItemStatusChangeModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('actionItemStatusChangeModalCloseBtn'), + ); + }); + + test('updates an action item status through the action item status change modal', async () => { + window.location.assign('/event/111/123'); + render( + + + + + + {} + + + + + , + ); + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('actionItemStatusChangeCheckbox')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('actionItemStatusChangeCheckbox')[0]); + + await waitFor(() => { + expect( + screen.getByTestId('actionItemsStatusChangeNotes'), + ).toBeInTheDocument(); + }); + + const postCompletionNotes = screen.getByTestId( + 'actionItemsStatusChangeNotes', + ); + fireEvent.change(postCompletionNotes, { target: { value: '' } }); + userEvent.type( + postCompletionNotes, + 'this action item has been completed successfully', + ); + + await waitFor(() => { + expect( + screen.getByTestId('actionItemStatusChangeSubmitBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('actionItemStatusChangeSubmitBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.successfulUpdation); + }); + + await waitFor(() => { + expect( + screen.getAllByTestId('actionItemStatusChangeCheckbox')[1], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('actionItemStatusChangeCheckbox')[1]); + + await waitFor(() => { + expect( + screen.getByTestId('actionItemsStatusChangeNotes'), + ).toBeInTheDocument(); + }); + + const preCompletionNotes = screen.getByTestId( + 'actionItemsStatusChangeNotes', + ); + fireEvent.change(preCompletionNotes, { target: { value: '' } }); + userEvent.type( + preCompletionNotes, + 'this action item has been made active again', + ); + + await waitFor(() => { + expect( + screen.getByTestId('actionItemStatusChangeSubmitBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('actionItemStatusChangeSubmitBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.successfulUpdation); + }); + }); + + test('Testing update action item modal', async () => { + window.location.assign('/event/111/123'); + render( + + + + + + {} + + + + + , + ); + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('editActionItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('editActionItemModalBtn')[0]); + + await waitFor(() => { + expect(screen.getByTestId('formUpdateAssignee')).toBeInTheDocument(); + }); + + userEvent.selectOptions( + screen.getByTestId('formUpdateAssignee'), + formData.assignee, + ); + + const preCompletionNotes = screen.getByPlaceholderText( + translations.preCompletionNotes, + ); + fireEvent.change(preCompletionNotes, { target: { value: '' } }); + userEvent.type(preCompletionNotes, formData.preCompletionNotes); + + const dueDatePicker = screen.getByLabelText(translations.dueDate); + fireEvent.change(dueDatePicker, { + target: { value: formData.dueDate }, + }); + + const completionDatePicker = screen.getByLabelText( + translations.completionDate, + ); + fireEvent.change(completionDatePicker, { + target: { value: formData.completionDate }, + }); + + await waitFor(() => { + expect( + screen.getByTestId('updateActionItemFormSubmitBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('updateActionItemFormSubmitBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.successfulUpdation); + }); + }); + test('Testing delete action item modal and delete the record', async () => { + window.location.assign('/event/111/123'); + render( + + + + + + {} + + + + + , + ); + await wait(); + expect( + screen.getAllByTestId('previewActionItemModalBtn')[0], + ).toBeInTheDocument(); + userEvent.click(screen.getAllByTestId('previewActionItemModalBtn')[0]); + + await waitFor(() => { + expect( + screen.getByTestId('deleteActionItemPreviewModalBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteActionItemPreviewModalBtn')); + await wait(); + expect( + screen.getByText(translations.deleteActionItemMsg), + ).toBeInTheDocument(); + userEvent.click(screen.getByText('Yes')); + await wait(); + + expect(toast.success).toBeCalledWith(translations.successfulDeletion); + }); + + test('Testing delete action item modal and does not delete the record', async () => { + window.location.assign('/event/111/123'); + render( + + + + + + {} + + + + + , + ); + await wait(); + expect( + screen.getAllByTestId('previewActionItemModalBtn')[0], + ).toBeInTheDocument(); + userEvent.click(screen.getAllByTestId('previewActionItemModalBtn')[0]); + + await waitFor(() => { + expect( + screen.getByTestId('deleteActionItemPreviewModalBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteActionItemPreviewModalBtn')); + await wait(); + expect( + screen.getByText(translations.deleteActionItemMsg), + ).toBeInTheDocument(); + userEvent.click(screen.getByText('No')); + await wait(); + expect(screen.getByRole('dialog')).toBeInTheDocument(); + expect( + screen.getByText(translations.actionItemDetails), + ).toBeInTheDocument(); + }); + + test('toasts error on unsuccessful deletion', async () => { + window.location.assign('/event/111/123'); + render( + + + + + + {} + + + + + , + ); + await wait(); + + expect( + screen.getAllByTestId('previewActionItemModalBtn')[0], + ).toBeInTheDocument(); + userEvent.click(screen.getAllByTestId('previewActionItemModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('previewActionItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + await waitFor(() => { + expect( + screen.getByTestId('deleteActionItemPreviewModalBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteActionItemPreviewModalBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('actionItemDeleteModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteActionItemBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); + + test('toasts error on unsuccessful updation', async () => { + window.location.assign('/event/111/123'); + render( + + + + + + {} + + + + + , + ); + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('editActionItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('editActionItemModalBtn')[0]); + + await waitFor(() => { + expect(screen.getByTestId('formUpdateAssignee')).toBeInTheDocument(); + }); + + userEvent.selectOptions( + screen.getByTestId('formUpdateAssignee'), + formData.assignee, + ); + + const preCompletionNotes = screen.getByPlaceholderText( + translations.preCompletionNotes, + ); + fireEvent.change(preCompletionNotes, { target: { value: '' } }); + userEvent.type(preCompletionNotes, formData.preCompletionNotes); + + const dueDatePicker = screen.getByLabelText(translations.dueDate); + fireEvent.change(dueDatePicker, { + target: { value: formData.dueDate }, + }); + + const completionDatePicker = screen.getByLabelText( + translations.completionDate, + ); + fireEvent.change(completionDatePicker, { + target: { value: formData.completionDate }, + }); + + await waitFor(() => { + expect( + screen.getByTestId('updateActionItemFormSubmitBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('updateActionItemFormSubmitBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); + + test('Raises an error when incorrect information is filled while creation', async () => { + window.location.assign('/event/111/123'); + render( + + + + + + {} + + + + + , + ); + await wait(); + userEvent.click(screen.getByTestId('createEventActionItemBtn')); + + await wait(); + expect( + screen.getByText(translations.actionItemDetails), + ).toBeInTheDocument(); + + fireEvent.change( + screen.getByPlaceholderText(translations.preCompletionNotes), + { + target: { value: 'task to be done with high priority' }, + }, + ); + expect( + screen.getByPlaceholderText(translations.preCompletionNotes), + ).toHaveValue('task to be done with high priority'); + + fireEvent.change(screen.getByLabelText(translations.dueDate), { + target: { value: '04/05/2024' }, + }); + expect(screen.getByLabelText(translations.dueDate)).toHaveValue( + '04/05/2024', + ); + + userEvent.click(screen.getByTestId('createActionItemFormSubmitBtn')); + await wait(); + + expect(toast.error).toBeCalled(); + }); + + test('Raises an error when incorrect information is filled while updation', async () => { + window.location.assign('/event/111/123'); + render( + + + + + + {} + + + + + , + ); + await wait(); + const updateButtons = screen.getAllByTestId('editActionItemModalBtn'); + userEvent.click(updateButtons[0]); + + expect( + screen.getByText(translations.actionItemDetails), + ).toBeInTheDocument(); + + userEvent.click(screen.getByTestId('updateActionItemFormSubmitBtn')); + + await wait(); + + expect(toast.error).toBeCalled(); + }); + + test('Displays message when no data is available', async () => { + window.location.assign('/event/111/123'); + render( + + + + + + {} + + + + + , + ); + await wait(); + expect(screen.getByText('Nothing Found !!')).toBeInTheDocument(); + }); + + test('Testing update action modal to have correct initial values', async () => { + window.location.assign('/event/111/123'); + render( + + + + + + {} + + + + + , + ); + await wait(); + const updateButtons = screen.getAllByTestId('editActionItemModalBtn'); + userEvent.click(updateButtons[0]); + + expect(screen.getByText('Action Item Details')).toBeInTheDocument(); + const assigneeDropdown = screen.getByTestId( + 'formUpdateAssignee', + ) as HTMLSelectElement; + expect(assigneeDropdown.value).toBe('658930fd2caa9d8d6908745c'); + expect(assigneeDropdown).toHaveTextContent('Teresa Bradley'); + + expect( + screen.getByPlaceholderText(translations.preCompletionNotes), + ).toHaveValue('Pre Completion Notes'); + const editActionItem = screen.getByRole('button', { + name: translations.editActionItem, + }); + expect(editActionItem).toBeInTheDocument(); + }); +}); diff --git a/src/components/EventManagement/EventActionItems/EventActionItems.tsx b/src/components/EventManagement/EventActionItems/EventActionItems.tsx new file mode 100644 index 0000000000..cbe878fa07 --- /dev/null +++ b/src/components/EventManagement/EventActionItems/EventActionItems.tsx @@ -0,0 +1,599 @@ +import { useMutation, useQuery } from '@apollo/client'; +import type { Dayjs } from 'dayjs'; +import dayjs from 'dayjs'; +import type { ChangeEvent } from 'react'; +import React, { useEffect, useState } from 'react'; +import { Button, Form } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; +import styles from './EventActionItems.module.css'; +import { DataGrid } from '@mui/x-data-grid'; +import type { GridCellParams } from '@mui/x-data-grid'; +import { Stack } from '@mui/material'; +import Modal from 'react-bootstrap/Modal'; +import { + CREATE_ACTION_ITEM_MUTATION, + DELETE_ACTION_ITEM_MUTATION, + UPDATE_ACTION_ITEM_MUTATION, +} from 'GraphQl/Mutations/ActionItemMutations'; +import type { + InterfaceActionItemCategoryList, + InterfaceActionItemInfo, + InterfaceMembersList, +} from 'utils/interfaces'; +import { DatePicker } from '@mui/x-date-pickers'; +import { + ACTION_ITEM_CATEGORY_LIST, + MEMBERS_LIST, +} from 'GraphQl/Queries/Queries'; +import { ACTION_ITEM_LIST_BY_EVENTS } from 'GraphQl/Queries/ActionItemQueries'; +import { useEventActionColumnConfig } from './useEventActionColumnConfig'; +import ActionItemPreviewModal from 'screens/OrganizationActionItems/ActionItemPreviewModal'; +import ActionItemDeleteModal from 'screens/OrganizationActionItems/ActionItemDeleteModal'; + +function eventActionItems(props: { eventId: string }): JSX.Element { + const { eventId } = props; + const { t } = useTranslation('translation', { + keyPrefix: 'eventActionItems', + }); + const { t: tCommon } = useTranslation('common'); + + const [actionItemPreviewModalIsOpen, setActionItemPreviewModalIsOpen] = + useState(false); + const [actionItemStatusModal, setActionItemStatusModal] = useState(false); + const [isActionItemCompleted, setIsActionItemCompleted] = useState(false); + const [assignmentDate, setAssignmentDate] = useState(new Date()); + const [actionItemCreateModalIsOpen, setActionItemCreateModalIsOpen] = + useState(false); + const [actionItemUpdateModalIsOpen, setActionItemUpdateModalIsOpen] = + useState(false); + const [actionItemDeleteModalIsOpen, setActionItemDeleteModalIsOpen] = + useState(false); + const [dueDate, setDueDate] = useState(new Date()); + const [completionDate, setCompletionDate] = useState(new Date()); + const [actionItemId, setActionItemId] = useState(''); + document.title = t('title'); + const url: string = window.location.href; + const startIdx: number = url.indexOf('/event/') + '/event/'.length; + const orgId: string = url.slice(startIdx, url.indexOf('/', startIdx)); + const [formState, setFormState] = useState({ + actionItemCategoryId: '', + assignee: '', + assigner: '', + assigneeId: '', + preCompletionNotes: '', + postCompletionNotes: '', + isCompleted: false, + }); + const showCreateModal = (): void => { + const newState = !actionItemCreateModalIsOpen; + setActionItemCreateModalIsOpen(newState); + }; + const hideCreateModal = (): void => { + setActionItemCreateModalIsOpen(!actionItemCreateModalIsOpen); + }; + const showUpdateModal = (): void => { + setActionItemUpdateModalIsOpen(!actionItemUpdateModalIsOpen); + }; + const hideUpdateModal = (): void => { + setActionItemId(''); + setActionItemUpdateModalIsOpen(!actionItemUpdateModalIsOpen); + }; + const toggleDeleteModal = (): void => { + setActionItemDeleteModalIsOpen(!actionItemDeleteModalIsOpen); + }; + const setActionItemState = (actionItem: InterfaceActionItemInfo): void => { + setFormState((prevState) => ({ + ...prevState, + assignee: `${actionItem.assignee.firstName} ${actionItem.assignee.lastName}`, + assigner: `${actionItem.assigner.firstName} ${actionItem.assigner.lastName}`, + assigneeId: actionItem.assignee._id, + preCompletionNotes: actionItem.preCompletionNotes, + postCompletionNotes: actionItem.postCompletionNotes, + isCompleted: actionItem.isCompleted, + })); + setActionItemId(actionItem._id); + setDueDate(actionItem.dueDate); + setAssignmentDate(actionItem.assignmentDate); + setCompletionDate(actionItem.completionDate); + }; + const { + data: actionItemCategoriesData, + }: { + data: InterfaceActionItemCategoryList | undefined; + loading: boolean; + error?: Error | undefined; + } = useQuery(ACTION_ITEM_CATEGORY_LIST, { + variables: { + organizationId: orgId, + }, + }); + const actionItemCategories = + actionItemCategoriesData?.actionItemCategoriesByOrganization.filter( + (category) => !category.isDisabled, + ); + const { data: actionItemsData, refetch: actionItemsRefetch } = useQuery( + ACTION_ITEM_LIST_BY_EVENTS, + { + variables: { + eventId, + }, + }, + ); + const { + data: membersData, + }: { + data: InterfaceMembersList | undefined; + loading: boolean; + error?: Error | undefined; + } = useQuery(MEMBERS_LIST, { + variables: { id: orgId }, + }); + const [createActionItem] = useMutation(CREATE_ACTION_ITEM_MUTATION); + const createActionItemHandler = async ( + e: ChangeEvent, + ): Promise => { + e.preventDefault(); + try { + await createActionItem({ + variables: { + assigneeId: formState.assigneeId, + actionItemCategoryId: formState.actionItemCategoryId, + eventId, + preCompletionNotes: formState.preCompletionNotes, + dueDate: dayjs(dueDate).format('YYYY-MM-DD'), + }, + }); + setFormState({ + actionItemCategoryId: '', + assignee: '', + assigner: '', + assigneeId: '', + preCompletionNotes: '', + postCompletionNotes: '', + isCompleted: false, + }); + setDueDate(new Date()); + actionItemsRefetch(); + hideCreateModal(); + toast.success(t('successfulCreation')); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + } + } + }; + useEffect(() => { + actionItemsRefetch({ + eventId, + }); + }, []); + const [updateActionItem] = useMutation(UPDATE_ACTION_ITEM_MUTATION); + const updateActionItemHandler = async ( + e: ChangeEvent, + ): Promise => { + e.preventDefault(); + try { + await updateActionItem({ + variables: { + actionItemId, + assigneeId: formState.assigneeId, + preCompletionNotes: formState.preCompletionNotes, + postCompletionNotes: formState.postCompletionNotes, + dueDate: dayjs(dueDate).format('YYYY-MM-DD'), + completionDate: dayjs(completionDate).format('YYYY-MM-DD'), + isCompleted: formState.isCompleted, + }, + }); + actionItemsRefetch(); + hideUpdateModal(); + hideActionItemStatusModal(); + toast.success(t('successfulUpdation')); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + } + } + }; + const [removeActionItem] = useMutation(DELETE_ACTION_ITEM_MUTATION); + const deleteActionItemHandler = async (): Promise => { + try { + await removeActionItem({ + variables: { + actionItemId, + }, + }); + actionItemsRefetch(); + toggleDeleteModal(); + hidePreviewModal(); + toast.success(t('successfulDeletion')); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + console.log(error.message); + } + } + }; + + const handleActionItemStatusChange = ( + actionItem: InterfaceActionItemInfo, + ): void => { + actionItem = { ...actionItem, isCompleted: !actionItem.isCompleted }; + setIsActionItemCompleted(!actionItem.isCompleted); + setActionItemState(actionItem); + setActionItemStatusModal(true); + }; + + const showPreviewModal = (actionItem: InterfaceActionItemInfo): void => { + setActionItemState(actionItem); + setActionItemPreviewModalIsOpen(true); + }; + + const handleEditClick = (actionItem: InterfaceActionItemInfo): void => { + setActionItemId(actionItem._id); + setActionItemState(actionItem); + showUpdateModal(); + }; + + const hidePreviewModal = (): void => { + setActionItemPreviewModalIsOpen(false); + }; + + const hideActionItemStatusModal = (): void => { + setActionItemStatusModal(false); + setActionItemUpdateModalIsOpen(false); + }; + + const { columns } = useEventActionColumnConfig({ + eventId, + handleActionItemStatusChange, + showPreviewModal, + handleEditClick, + }); + + return ( + <> + +
    + {/* create action item modal */} + + +

    {t('actionItemDetails')}

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

    {t('actionItemDetails')}

    + +
    + +
    + + Assignee + + setFormState({ ...formState, assigneeId: e.target.value }) + } + > + + {membersData?.organizations[0].members.map((member, index) => { + const currMemberName = `${member.firstName} ${member.lastName}`; + if (currMemberName !== formState.assignee) { + return ( + + ); + } + })} + + + + { + setFormState({ + ...formState, + preCompletionNotes: e.target.value, + }); + }} + /> +
    + { + if (date) { + setDueDate(date?.toDate()); + } + }} + /> +   + { + /* istanbul ignore next */ + if (date) { + setCompletionDate(date?.toDate()); + } + } + } + /> +
    +
    + +
    + +
    +
    + + {/* preview modal */} + + + {/* Delete Modal */} + + + {/* action item status change modal */} + + +

    {t('actionItemStatus')}

    + +
    + +
    + + {isActionItemCompleted + ? t('preCompletionNotes') + : t('postCompletionNotes')} + + { + if (isActionItemCompleted) { + setFormState({ + ...formState, + preCompletionNotes: e.target.value, + }); + } else { + setFormState({ + ...formState, + postCompletionNotes: e.target.value, + }); + } + }} + /> + + +
    +
    + {actionItemsData && ( +
    + row._id} + slots={{ + noRowsOverlay: () => ( + + Nothing Found !! + + ), + }} + sx={{ + '&.MuiDataGrid-root .MuiDataGrid-cell:focus-within': { + outline: 'none !important', + }, + '&.MuiDataGrid-root .MuiDataGrid-columnHeader:focus-within': { + outline: 'none', + }, + '& .MuiDataGrid-row:hover': { + backgroundColor: 'transparent', + }, + '& .MuiDataGrid-row.Mui-hovered': { + backgroundColor: 'transparent', + }, + '& .MuiDataGrid-columnHeaderTitle': { + fontWeight: 700, + }, + }} + getRowClassName={() => `${styles.rowBackground}`} + autoHeight + rowHeight={50} + columnHeaderHeight={40} + rows={actionItemsData?.actionItemsByEvent?.map( + (item: object, index: number) => ({ + ...item, + index: index + 1, + }), + )} + columns={columns} + isRowSelectable={() => false} + /> +
    + )} + + ); +} +export default eventActionItems; diff --git a/src/components/EventManagement/EventActionItems/useEventActionColumnConfig.tsx b/src/components/EventManagement/EventActionItems/useEventActionColumnConfig.tsx new file mode 100644 index 0000000000..0db74323f6 --- /dev/null +++ b/src/components/EventManagement/EventActionItems/useEventActionColumnConfig.tsx @@ -0,0 +1,200 @@ +import React from 'react'; +import type { GridCellParams, GridColDef } from '@mui/x-data-grid'; +import { Link } from 'react-router-dom'; +import { Button, OverlayTrigger, Popover } from 'react-bootstrap'; +import styles from './EventActionItems.module.css'; +import type { InterfaceActionItemInfo } from 'utils/interfaces'; +import { useTranslation } from 'react-i18next'; + +export type Props = { + eventId: string; + handleActionItemStatusChange: (actionItem: InterfaceActionItemInfo) => void; + showPreviewModal: (actionItem: InterfaceActionItemInfo) => void; + handleEditClick: (actionItem: InterfaceActionItemInfo) => void; +}; + +type ColumnConfig = { + columns: GridColDef[]; +}; + +const popover = ( + actionItemId: string, + actionItemNotes: string, +): JSX.Element => { + return ( + + {actionItemNotes} + + ); +}; + +export const useEventActionColumnConfig = ({ + eventId, + handleActionItemStatusChange, + showPreviewModal, + handleEditClick, +}: Props): ColumnConfig => { + const { t } = useTranslation('translation', { + keyPrefix: 'eventActionItems', + }); + const columns: GridColDef[] = [ + { + field: 'serialNo', + headerName: '#', + flex: 1, + minWidth: 50, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return params.row?.index; + }, + }, + { + field: 'assignee', + headerName: 'Assignee', + flex: 2, + minWidth: 150, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return ( + + {params.row?.assignee.firstName + + ' ' + + params.row?.assignee.lastName} + + ); + }, + }, + { + field: 'actionItemCategory', + headerName: 'Action Item Category', + flex: 2, + minWidth: 100, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return params.row.actionItemCategory.name; + }, + }, + { + field: 'notes', + headerName: 'Notes', + minWidth: 150, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + flex: 2, + sortable: false, + renderCell: (params: GridCellParams) => { + const actionItem = params.row; + return ( + + + {actionItem.preCompletionNotes.length > 25 + ? `${actionItem.preCompletionNotes.substring(0, 25)}...` + : actionItem.preCompletionNotes} + + + ); + }, + }, + { + field: 'completionNotes', + headerName: 'Completion Notes', + minWidth: 150, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + flex: 2, + sortable: false, + renderCell: (params: GridCellParams) => { + const actionItem = params.row; + return actionItem.isCompleted ? ( + + + {actionItem.postCompletionNotes?.length > 25 + ? `${actionItem.postCompletionNotes.substring(0, 25)}...` + : actionItem.postCompletionNotes} + + + ) : ( + + {t('actionItemActive')} + + ); + }, + }, + { + field: 'options', + headerName: 'Options', + flex: 2, + minWidth: 100, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return ( +
    + handleActionItemStatusChange(params.row)} + /> + + +
    + ); + }, + }, + ]; + return { + columns, + }; +}; diff --git a/src/components/EventManagement/EventAgendaItems/EventAgendaItems.module.css b/src/components/EventManagement/EventAgendaItems/EventAgendaItems.module.css new file mode 100644 index 0000000000..9d1c32b766 --- /dev/null +++ b/src/components/EventManagement/EventAgendaItems/EventAgendaItems.module.css @@ -0,0 +1,22 @@ +.eventAgendaItemContainer h2 { + margin: 0.6rem 0; +} + +.btnsContainer { + display: flex; + gap: 10px; +} + +@media (max-width: 768px) { + .btnsContainer { + margin-bottom: 0; + display: flex; + flex-direction: column; + } + + .createAgendaItemButton { + position: absolute; + top: 1rem; + right: 2rem; + } +} diff --git a/src/components/EventManagement/EventAgendaItems/EventAgendaItems.test.tsx b/src/components/EventManagement/EventAgendaItems/EventAgendaItems.test.tsx new file mode 100644 index 0000000000..b1b3ed6094 --- /dev/null +++ b/src/components/EventManagement/EventAgendaItems/EventAgendaItems.test.tsx @@ -0,0 +1,205 @@ +import React from 'react'; +import { + render, + screen, + waitFor, + act, + waitForElementToBeRemoved, +} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import 'jest-localstorage-mock'; +import { MockedProvider } from '@apollo/client/testing'; +import 'jest-location-mock'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import i18n from 'utils/i18nForTest'; +import { toast } from 'react-toastify'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; + +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; + +import EventAgendaItems from './EventAgendaItems'; + +import { + MOCKS, + MOCKS_ERROR_QUERY, + MOCKS_ERROR_MUTATION, +} from './EventAgendaItemsMocks'; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ eventId: '123' }), +})); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(MOCKS_ERROR_QUERY, true); +const link3 = new StaticMockLink(MOCKS_ERROR_MUTATION, true); + +const translations = JSON.parse( + JSON.stringify(i18n.getDataByLanguage('en')?.translation.agendaItems), +); + +describe('Testing Agenda Items Components', () => { + const formData = { + title: 'AgendaItem 1', + description: 'AgendaItem 1 Description', + duration: '30', + relatedEventId: '123', + organizationId: '111', + sequence: 1, + categories: ['Category 1'], + attachments: [], + urls: [], + }; + test('Component loads correctly', async () => { + window.location.assign('/event/111/123'); + const { getByText } = render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(getByText(translations.createAgendaItem)).toBeInTheDocument(); + }); + }); + + test('render error component on unsuccessful agenda item query', async () => { + window.location.assign('/event/111/123'); + const { queryByText } = render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + queryByText(translations.createAgendaItem), + ).not.toBeInTheDocument(); + }); + }); + + test('opens and closes the create agenda item modal', async () => { + window.location.assign('/event/111/123'); + render( + + + + + + {} + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createAgendaItemBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('createAgendaItemBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('createAgendaItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('createAgendaItemModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('createAgendaItemModalCloseBtn'), + ); + }); + test('creates new agenda item', async () => { + window.location.assign('/event/111/123'); + render( + + + + + + {} + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createAgendaItemBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('createAgendaItemBtn')); + + await waitFor(() => { + expect( + screen.getByTestId('createAgendaItemModalCloseBtn'), + ).toBeInTheDocument(); + }); + + userEvent.type( + screen.getByPlaceholderText(translations.enterTitle), + formData.title, + ); + + userEvent.type( + screen.getByPlaceholderText(translations.enterDescription), + formData.description, + ); + userEvent.type( + screen.getByPlaceholderText(translations.enterDuration), + formData.duration, + ); + const categorySelect = screen.getByTestId('categorySelect'); + userEvent.click(categorySelect); + await waitFor(() => { + const categoryOption = screen.getByText('Category 1'); + userEvent.click(categoryOption); + }); + + userEvent.click(screen.getByTestId('createAgendaItemFormBtn')); + + await waitFor(() => { + // expect(toast.success).toBeCalledWith(translations.agendaItemCreated); + }); + }); +}); diff --git a/src/components/EventManagement/EventAgendaItems/EventAgendaItems.tsx b/src/components/EventManagement/EventAgendaItems/EventAgendaItems.tsx new file mode 100644 index 0000000000..09cc560bf1 --- /dev/null +++ b/src/components/EventManagement/EventAgendaItems/EventAgendaItems.tsx @@ -0,0 +1,203 @@ +import React, { useState } from 'react'; +import type { ChangeEvent } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Button } from 'react-bootstrap'; + +import { WarningAmberRounded } from '@mui/icons-material'; +import { toast } from 'react-toastify'; + +import { useMutation, useQuery } from '@apollo/client'; +import { + AGENDA_ITEM_CATEGORY_LIST, + AgendaItemByEvent, +} from 'GraphQl/Queries/Queries'; +import { CREATE_AGENDA_ITEM_MUTATION } from 'GraphQl/Mutations/mutations'; + +import type { + InterfaceAgendaItemCategoryList, + InterfaceAgendaItemList, +} from 'utils/interfaces'; +import AgendaItemsContainer from 'components/AgendaItems/AgendaItemsContainer'; +import AgendaItemsCreateModal from 'components/AgendaItems/AgendaItemsCreateModal'; + +import styles from './EventAgendaItems.module.css'; +import Loader from 'components/Loader/Loader'; + +function EventAgendaItems(props: { eventId: string }): JSX.Element { + const { eventId } = props; + + const { t } = useTranslation('translation', { + keyPrefix: 'agendaItems', + }); + + const url: string = window.location.href; + const startIdx: number = url.indexOf('/event/') + '/event/'.length; + const orgId: string = url.slice(startIdx, url.indexOf('/', startIdx)); + + const [agendaItemCreateModalIsOpen, setAgendaItemCreateModalIsOpen] = + useState(false); + + const [formState, setFormState] = useState({ + agendaItemCategoryIds: [''], + title: '', + description: '', + duration: '', + attachments: [''], + urls: [''], + }); + + const { + data: agendaCategoryData, + loading: agendaCategoryLoading, + error: agendaCategoryError, + }: { + data: InterfaceAgendaItemCategoryList | undefined; + loading: boolean; + error?: Error | undefined; + } = useQuery(AGENDA_ITEM_CATEGORY_LIST, { + variables: { organizationId: orgId }, + notifyOnNetworkStatusChange: true, + }); + + const { + data: agendaItemData, + loading: agendaItemLoading, + error: agendaItemError, + refetch: refetchAgendaItem, + }: { + data: InterfaceAgendaItemList | undefined; + loading: boolean; + error?: unknown | undefined; + refetch: () => void; + } = useQuery(AgendaItemByEvent, { + variables: { relatedEventId: eventId }, //eventId + notifyOnNetworkStatusChange: true, + }); + + const [createAgendaItem] = useMutation(CREATE_AGENDA_ITEM_MUTATION); + + const createAgendaItemHandler = async ( + e: ChangeEvent, + ): Promise => { + e.preventDefault(); + try { + await createAgendaItem({ + variables: { + input: { + title: formState.title, + description: formState.description, + relatedEventId: eventId, + organizationId: orgId, + sequence: (agendaItemData?.agendaItemByEvent.length || 0) + 1 || 1, // Assign sequence based on current length + duration: formState.duration, + categories: formState.agendaItemCategoryIds, + attachments: formState.attachments, + urls: formState.urls, + }, + }, + }); + + setFormState({ + title: '', + description: '', + duration: '', + agendaItemCategoryIds: [''], + attachments: [''], + urls: [''], + }); + hideCreateModal(); + refetchAgendaItem(); + toast.success(t('agendaItemCreated')); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + } + } + }; + + const showCreateModal = (): void => { + setAgendaItemCreateModalIsOpen(!agendaItemCreateModalIsOpen); + }; + + const hideCreateModal = (): void => { + setAgendaItemCreateModalIsOpen(!agendaItemCreateModalIsOpen); + }; + + if (agendaItemLoading || agendaCategoryLoading) return ; + + if (agendaItemError || agendaCategoryError) { + return ( +
    +
    + +
    + Error occurred while loading{' '} + {agendaCategoryError + ? 'Agenda Categories' + : agendaItemError && 'Agenda Items'} + Data +
    + {agendaCategoryError + ? agendaCategoryError.message + : agendaItemError && (agendaItemError as Error).message} +
    +
    +
    + ); + } + + return ( +
    +
    +
    +
    +
    + {/* setSearchValue(e.target.value)} + value={searchValue} + data-testid="search" + /> */} +
    + + +
    +
    + +
    + + +
    + + +
    + ); +} + +export default EventAgendaItems; diff --git a/src/components/EventManagement/EventAgendaItems/EventAgendaItemsMocks.ts b/src/components/EventManagement/EventAgendaItems/EventAgendaItemsMocks.ts new file mode 100644 index 0000000000..619a1e70f8 --- /dev/null +++ b/src/components/EventManagement/EventAgendaItems/EventAgendaItemsMocks.ts @@ -0,0 +1,133 @@ +import { CREATE_AGENDA_ITEM_MUTATION } from 'GraphQl/Mutations/AgendaItemMutations'; + +import { AgendaItemByEvent } from 'GraphQl/Queries/AgendaItemQueries'; +import { AGENDA_ITEM_CATEGORY_LIST } from 'GraphQl/Queries/AgendaCategoryQueries'; + +export const MOCKS = [ + { + request: { + query: AGENDA_ITEM_CATEGORY_LIST, + variables: { organizationId: '111' }, + }, + result: { + data: { + agendaItemCategoriesByOrganization: [ + { + _id: 'agendaItemCategory1', + name: 'Category 1', + description: 'Test Description', + createdBy: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + ], + }, + }, + }, + { + request: { + query: AgendaItemByEvent, + variables: { relatedEventId: '123' }, + }, + result: { + data: { + agendaItemByEvent: [ + { + _id: 'agendaItem1', + title: 'AgendaItem 1', + description: 'AgendaItem 1 Description', + duration: '30', + attachments: [], + createdBy: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + urls: [], + users: [], + sequence: 1, + categories: [ + { + _id: 'agendaItemCategory1', + name: 'Category 1', + }, + ], + organization: { + _id: '111', + name: 'Unity Foundation', + }, + relatedEvent: { + _id: '123', + title: 'Aerobics for Everyone', + }, + }, + ], + }, + }, + }, + { + request: { + query: CREATE_AGENDA_ITEM_MUTATION, + variables: { + input: { + title: 'AgendaItem 1', + description: 'AgendaItem 1 Description', + duration: '30', + relatedEventId: '123', + organizationId: '111', + sequence: 1, + categories: ['Category 1'], + attachments: [], + urls: [], + }, + }, + }, + result: { + data: { + createAgendaItem: { + _id: 'agendaItem1', + }, + }, + }, + }, +]; + +export const MOCKS_ERROR_MUTATION = [ + { + request: { + query: CREATE_AGENDA_ITEM_MUTATION, + variables: { + input: { + title: 'AgendaItem 1', + description: 'AgendaItem 1 Description', + duration: '30', + relatedEventId: '123', + organizationId: '111', + sequence: 1, + categories: ['agendaItemCategory1'], + attachments: [], + urls: [], + }, + }, + }, + error: new Error('Mock Graphql Error'), + }, + { + request: { + query: AgendaItemByEvent, + variables: { relatedEventId: '123' }, + }, + error: new Error('Mock Graphql Error'), + }, + { + request: { + query: AGENDA_ITEM_CATEGORY_LIST, + variables: { organizationId: '111' }, + }, + error: new Error('Mock Graphql Error'), + }, +]; + +export const MOCKS_ERROR_QUERY = []; diff --git a/src/components/EventRegistrantsModal/EventRegistrantsModal.module.css b/src/components/EventRegistrantsModal/EventRegistrantsModal.module.css new file mode 100644 index 0000000000..0f78d81c01 --- /dev/null +++ b/src/components/EventRegistrantsModal/EventRegistrantsModal.module.css @@ -0,0 +1,43 @@ +.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/components/EventRegistrantsModal/EventRegistrantsModal.test.tsx b/src/components/EventRegistrantsModal/EventRegistrantsModal.test.tsx new file mode 100644 index 0000000000..8a084fef24 --- /dev/null +++ b/src/components/EventRegistrantsModal/EventRegistrantsModal.test.tsx @@ -0,0 +1,328 @@ +import React from 'react'; +import { fireEvent, render, waitFor } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { EventRegistrantsModal } from './EventRegistrantsModal'; +import { EVENT_ATTENDEES, MEMBERS_LIST } from 'GraphQl/Queries/Queries'; +import { + ADD_EVENT_ATTENDEE, + REMOVE_EVENT_ATTENDEE, +} from 'GraphQl/Mutations/mutations'; +import { BrowserRouter } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import { I18nextProvider } from 'react-i18next'; +import i18nForTest from 'utils/i18nForTest'; +import { ToastContainer } from 'react-toastify'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; + +const queryMockWithoutRegistrant = [ + { + request: { + query: EVENT_ATTENDEES, + variables: { id: 'event123' }, + }, + result: { + data: { + event: { + attendees: [], + }, + }, + }, + }, +]; + +const queryMockWithRegistrant = [ + { + request: { + query: EVENT_ATTENDEES, + variables: { id: 'event123' }, + }, + result: { + data: { + event: { + attendees: [{ _id: 'user1', firstName: 'John', lastName: 'Doe' }], + }, + }, + }, + }, +]; + +const queryMockOrgMembers = [ + { + request: { + query: MEMBERS_LIST, + variables: { id: 'org123' }, + }, + result: { + data: { + organizations: [ + { + _id: 'org123', + members: [ + { + _id: 'user1', + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@palisadoes.com', + image: '', + createdAt: '12/12/22', + organizationsBlockedBy: [], + }, + ], + }, + ], + }, + }, + }, +]; + +const successfulAddRegistrantMock = [ + { + request: { + query: ADD_EVENT_ATTENDEE, + variables: { userId: 'user1', eventId: 'event123' }, + }, + result: { + data: { + addEventAttendee: { _id: 'user1' }, + }, + }, + }, +]; + +const unsuccessfulAddRegistrantMock = [ + { + request: { + query: ADD_EVENT_ATTENDEE, + variables: { userId: 'user1', eventId: 'event123' }, + }, + error: new Error('Oops'), + }, +]; + +const successfulRemoveRegistrantMock = [ + { + request: { + query: REMOVE_EVENT_ATTENDEE, + variables: { userId: 'user1', eventId: 'event123' }, + }, + result: { + data: { + removeEventAttendee: { _id: 'user1' }, + }, + }, + }, +]; + +const unsuccessfulRemoveRegistrantMock = [ + { + request: { + query: REMOVE_EVENT_ATTENDEE, + variables: { userId: 'user1', eventId: 'event123' }, + }, + error: new Error('Oops'), + }, +]; + +describe('Testing Event Registrants Modal', () => { + const props = { + show: true, + eventId: 'event123', + orgId: 'org123', + handleClose: jest.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 () => { + const { queryByText, queryByLabelText } = render( + + + + + + + + + + + + , + ); + + await waitFor(() => + expect(queryByText('Event Registrants')).toBeInTheDocument(), + ); + + await waitFor(() => + expect(queryByText('Registered Registrants')).toBeInTheDocument(), + ); + + await waitFor(() => + expect( + queryByText('There are no registered attendees for this event.'), + ).toBeInTheDocument(), + ); + + // Get warning modal on blank button click + fireEvent.click(queryByText('Add Registrant') as Element); + + await waitFor(() => + expect( + queryByText('Please choose an user to add first!'), + ).toBeInTheDocument(), + ); + + // Choose a user to add as an attendee + const attendeeInput = queryByLabelText('Add an Registrant'); + fireEvent.change(attendeeInput as Element, { + target: { value: 'John Doe' }, + }); + fireEvent.keyDown(attendeeInput as HTMLElement, { key: 'ArrowDown' }); + fireEvent.keyDown(attendeeInput as HTMLElement, { key: 'Enter' }); + + fireEvent.click(queryByText('Add Registrant') as Element); + + await waitFor(() => + expect(queryByText('Adding the attendee...')).toBeInTheDocument(), + ); + + await waitFor(() => + expect(queryByText('Attendee added Successfully')).toBeInTheDocument(), + ); + }); + + test('Add attendee mutation must fail properly', async () => { + const { queryByText, queryByLabelText } = render( + + + + + + + + + + + + , + ); + + await waitFor(() => + expect( + queryByText('There are no registered attendees for this event.'), + ).toBeInTheDocument(), + ); + + // Choose a user to add as an attendee + const attendeeInput = queryByLabelText('Add an Registrant'); + fireEvent.change(attendeeInput as Element, { + target: { value: 'John Doe' }, + }); + fireEvent.keyDown(attendeeInput as HTMLElement, { key: 'ArrowDown' }); + fireEvent.keyDown(attendeeInput as HTMLElement, { key: 'Enter' }); + + fireEvent.click(queryByText('Add Registrant') as Element); + + await waitFor(() => + expect(queryByText('Adding the attendee...')).toBeInTheDocument(), + ); + + await waitFor(() => + expect(queryByText('Error adding attendee')).toBeInTheDocument(), + ); + }); + + test('Assigned attendees must be shown with badges and delete attendee mutation must function properly', async () => { + const { queryByText, queryByTestId } = render( + + + + + + + + + + + + , + ); + + await waitFor(() => + expect(queryByText('Registered Registrants')).toBeInTheDocument(), + ); + + await waitFor(() => expect(queryByText('John Doe')).toBeInTheDocument()); + + fireEvent.click(queryByTestId('CancelIcon') as Element); + + await waitFor(() => + expect(queryByText('Removing the attendee...')).toBeInTheDocument(), + ); + + await waitFor(() => + expect(queryByText('Attendee removed Successfully')).toBeInTheDocument(), + ); + }); + + test('Delete attendee mutation must fail properly', async () => { + const { queryByText, queryByTestId } = render( + + + + + + + + + + + + , + ); + + await waitFor(() => + expect(queryByText('Registered Registrants')).toBeInTheDocument(), + ); + + await waitFor(() => expect(queryByText('John Doe')).toBeInTheDocument()); + + fireEvent.click(queryByTestId('CancelIcon') as Element); + + await waitFor(() => + expect(queryByText('Removing the attendee...')).toBeInTheDocument(), + ); + + await waitFor(() => + expect(queryByText('Error removing attendee')).toBeInTheDocument(), + ); + }); +}); diff --git a/src/components/EventRegistrantsModal/EventRegistrantsModal.tsx b/src/components/EventRegistrantsModal/EventRegistrantsModal.tsx new file mode 100644 index 0000000000..811dd44941 --- /dev/null +++ b/src/components/EventRegistrantsModal/EventRegistrantsModal.tsx @@ -0,0 +1,156 @@ +import React, { useState } from 'react'; +import { Modal, Button } from 'react-bootstrap'; +import { toast } from 'react-toastify'; +import { useMutation, useQuery } from '@apollo/client'; +import { EVENT_ATTENDEES, MEMBERS_LIST } from 'GraphQl/Queries/Queries'; +import { + ADD_EVENT_ATTENDEE, + REMOVE_EVENT_ATTENDEE, +} from 'GraphQl/Mutations/mutations'; +import styles from 'components/EventRegistrantsModal/EventRegistrantsModal.module.css'; +import Avatar from '@mui/material/Avatar'; +import Chip from '@mui/material/Chip'; +import Stack from '@mui/material/Stack'; +import TextField from '@mui/material/TextField'; +import Autocomplete from '@mui/material/Autocomplete'; +import { useTranslation } from 'react-i18next'; + +type ModalPropType = { + show: boolean; + eventId: string; + orgId: string; + handleClose: () => void; +}; + +interface InterfaceUser { + _id: string; + firstName: string; + lastName: string; +} + +export const EventRegistrantsModal = (props: ModalPropType): JSX.Element => { + const { eventId, orgId, handleClose, show } = props; + const [member, setMember] = useState(null); + + const [addRegistrantMutation] = useMutation(ADD_EVENT_ATTENDEE); + const [removeRegistrantMutation] = useMutation(REMOVE_EVENT_ATTENDEE); + + const { t } = useTranslation('translation', { + keyPrefix: 'eventRegistrantsModal', + }); + const { t: tCommon } = useTranslation('common'); + const { + data: attendeesData, + loading: attendeesLoading, + refetch: attendeesRefetch, + } = useQuery(EVENT_ATTENDEES, { + variables: { id: eventId }, + }); + + const { data: memberData, loading: memberLoading } = useQuery(MEMBERS_LIST, { + variables: { id: orgId }, + }); + + const addRegistrant = (): void => { + if (member == null) { + toast.warning('Please choose an user to add first!'); + return; + } + toast.warn('Adding the attendee...'); + addRegistrantMutation({ + variables: { + userId: member._id, + eventId: eventId, + }, + }) + .then(() => { + toast.success(tCommon('addedSuccessfully', { item: 'Attendee' })); + attendeesRefetch(); + }) + .catch((err) => { + toast.error(t('errorAddingAttendee')); + toast.error(err.message); + }); + }; + + const deleteRegistrant = (userId: string): void => { + toast.warn('Removing the attendee...'); + removeRegistrantMutation({ + variables: { + userId, + eventId: eventId, + }, + }) + .then(() => { + toast.success(tCommon('removedSuccessfully', { item: 'Attendee' })); + attendeesRefetch(); + }) + .catch((err) => { + toast.error(t('errorRemovingAttendee')); + toast.error(err.message); + }); + }; + + // Render the loading screen + if (attendeesLoading || memberLoading) { + return ( + <> +
    + + ); + } + + return ( + <> + + + Event Registrants + + +
    Registered Registrants
    + {attendeesData.event.attendees.length == 0 + ? `There are no registered attendees for this event.` + : null} + + {attendeesData.event.attendees.map((attendee: InterfaceUser) => ( + {`${attendee.firstName[0]}${attendee.lastName[0]}`} + } + label={`${attendee.firstName} ${attendee.lastName}`} + variant="outlined" + key={attendee._id} + onDelete={(): void => deleteRegistrant(attendee._id)} + /> + ))} + +
    + + { + setMember(newMember); + }} + options={memberData.organizations[0].members} + getOptionLabel={(member: InterfaceUser): string => + `${member.firstName} ${member.lastName}` + } + renderInput={(params): React.ReactNode => ( + + )} + /> +
    +
    + + + +
    + + ); +}; diff --git a/src/components/EventRegistrantsModal/EventRegistrantsWrapper.module.css b/src/components/EventRegistrantsModal/EventRegistrantsWrapper.module.css new file mode 100644 index 0000000000..59b31333af --- /dev/null +++ b/src/components/EventRegistrantsModal/EventRegistrantsWrapper.module.css @@ -0,0 +1,13 @@ +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.test.tsx new file mode 100644 index 0000000000..d1707e8520 --- /dev/null +++ b/src/components/EventRegistrantsModal/EventRegistrantsWrapper.test.tsx @@ -0,0 +1,92 @@ +import React from 'react'; +import { fireEvent, render, waitFor } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { EventRegistrantsWrapper } from './EventRegistrantsWrapper'; +import { EVENT_ATTENDEES, MEMBERS_LIST } from 'GraphQl/Queries/Queries'; +import { BrowserRouter } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import { I18nextProvider } from 'react-i18next'; +import i18nForTest from 'utils/i18nForTest'; +import { ToastContainer } from 'react-toastify'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; + +const queryMock = [ + { + request: { + query: EVENT_ATTENDEES, + variables: { id: 'event123' }, + }, + result: { + data: { + event: { + attendees: [], + }, + }, + }, + }, + { + request: { + query: MEMBERS_LIST, + variables: { id: 'org123' }, + }, + result: { + data: { + organizations: [ + { + _id: 'org123', + members: [ + { + _id: 'user1', + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@palisadoes.com', + image: '', + createdAt: '12/12/22', + organizationsBlockedBy: [], + }, + ], + }, + ], + }, + }, + }, +]; + +describe('Testing Event Registrants Wrapper', () => { + const props = { + eventId: 'event123', + orgId: 'org123', + }; + + test('The button should work properly', async () => { + const { queryByText, queryByRole } = render( + + + + + + + + + + + + , + ); + + // Open the modal + fireEvent.click(queryByText('Show Registrants') as Element); + + await waitFor(() => + expect(queryByText('Event Registrants')).toBeInTheDocument(), + ); + + // Close the modal + fireEvent.click(queryByRole('button', { name: /close/i }) as HTMLElement); + await waitFor(() => + expect(queryByText('Event Registrants')).not.toBeInTheDocument(), + ); + }); +}); diff --git a/src/components/EventRegistrantsModal/EventRegistrantsWrapper.tsx b/src/components/EventRegistrantsModal/EventRegistrantsWrapper.tsx new file mode 100644 index 0000000000..b621f8673a --- /dev/null +++ b/src/components/EventRegistrantsModal/EventRegistrantsWrapper.tsx @@ -0,0 +1,46 @@ +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'; + +type PropType = { + eventId: string; + orgId: string; +}; + +export const EventRegistrantsWrapper = (props: PropType): JSX.Element => { + const [showModal, setShowModal] = useState(false); + + return ( + <> + + + {showModal && ( + { + setShowModal(false); + }} + eventId={props.eventId} + orgId={props.orgId} + /> + )} + + ); +}; diff --git a/src/components/EventStats/EventStats.module.css b/src/components/EventStats/EventStats.module.css new file mode 100644 index 0000000000..44ba75a0a8 --- /dev/null +++ b/src/components/EventStats/EventStats.module.css @@ -0,0 +1,35 @@ +.stackEvents { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + margin: 10px 20px; + padding: 10px 20px; + overflow: hidden; + gap: 2px; + column-gap: 2px; +} + +@media screen and (min-width: 801px) { + .stackEvents { + flex-direction: row; + justify-content: space-between; + align-items: flex-start; + padding: 0 2rem; + margin: 0 40px; + gap: 5px; + column-gap: 4px; + } +} + +@media screen and (min-width: 768px) and (max-width: 800px) { + .stackEvents { + flex-direction: row; + justify-content: space-between; + align-items: flex-start; + padding: 0 2rem; + margin: 0 20px; + gap: 5px; + column-gap: 4px; + } +} diff --git a/src/components/EventStats/EventStats.test.tsx b/src/components/EventStats/EventStats.test.tsx new file mode 100644 index 0000000000..e2496fa5af --- /dev/null +++ b/src/components/EventStats/EventStats.test.tsx @@ -0,0 +1,62 @@ +import React from 'react'; +import { render, waitFor } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { EventStats } from './EventStats'; +import { BrowserRouter } from 'react-router-dom'; +import { EVENT_FEEDBACKS } from 'GraphQl/Queries/Queries'; + +// Mock the modules for PieChart rendering as they require a trasformer being used (which is not done by Jest) +// These modules are used by the Feedback component +jest.mock('@mui/x-charts/PieChart', () => ({ + pieArcLabelClasses: jest.fn(), + PieChart: jest.fn().mockImplementation(() => <>Test), + pieArcClasses: jest.fn(), +})); + +const mockData = [ + { + request: { + query: EVENT_FEEDBACKS, + variables: { + id: 'eventStats123', + }, + }, + result: { + data: { + event: { + _id: 'eventStats123', + feedback: [ + { + _id: 'feedback1', + review: 'review1', + rating: 5, + }, + ], + averageFeedbackScore: 5, + }, + }, + }, + }, +]; + +describe('Testing Event Stats', () => { + const props = { + eventId: 'eventStats123', + show: true, + handleClose: jest.fn(), + }; + + test('The stats should be rendered properly', async () => { + const { queryByText } = render( + + + + + , + ); + + await waitFor(() => + expect(queryByText('Event Statistics')).toBeInTheDocument(), + ); + }); +}); diff --git a/src/components/EventStats/EventStats.tsx b/src/components/EventStats/EventStats.tsx new file mode 100644 index 0000000000..c9f1a70e8d --- /dev/null +++ b/src/components/EventStats/EventStats.tsx @@ -0,0 +1,57 @@ +import React from 'react'; +import { Modal } from 'react-bootstrap'; +import { FeedbackStats } from './Statistics/Feedback'; +import { ReviewStats } from './Statistics/Review'; +import { AverageRating } from './Statistics/AverageRating'; +import styles from './Loader.module.css'; +import eventStatsStyles from './EventStats.module.css'; +import { useQuery } from '@apollo/client'; +import { EVENT_FEEDBACKS } from 'GraphQl/Queries/Queries'; + +type ModalPropType = { + show: boolean; + eventId: string; + handleClose: () => void; +}; + +export const EventStats = ({ + show, + handleClose, + eventId, +}: ModalPropType): JSX.Element => { + const { data, loading } = useQuery(EVENT_FEEDBACKS, { + variables: { id: eventId }, + }); + + // Render the loading screen + if (loading) { + return ( + <> +
    + + ); + } + + return ( + <> + + + Event Statistics + + + +
    + + +
    +
    +
    + + ); +}; diff --git a/src/components/EventStats/EventStatsWrapper.module.css b/src/components/EventStats/EventStatsWrapper.module.css new file mode 100644 index 0000000000..f5f42546c3 --- /dev/null +++ b/src/components/EventStats/EventStatsWrapper.module.css @@ -0,0 +1,13 @@ +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/EventStats/EventStatsWrapper.test.tsx b/src/components/EventStats/EventStatsWrapper.test.tsx new file mode 100644 index 0000000000..0e64ac13cc --- /dev/null +++ b/src/components/EventStats/EventStatsWrapper.test.tsx @@ -0,0 +1,76 @@ +import React from 'react'; +import { fireEvent, render, waitFor } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { EventStatsWrapper } from './EventStatsWrapper'; +import { BrowserRouter } from 'react-router-dom'; +import { EVENT_FEEDBACKS } from 'GraphQl/Queries/Queries'; + +// Mock the modules for PieChart rendering as they require a trasformer being used (which is not done by Jest) +jest.mock('@mui/x-charts/PieChart', () => ({ + pieArcLabelClasses: jest.fn(), + PieChart: jest.fn().mockImplementation(() => <>Test), + pieArcClasses: jest.fn(), +})); + +const mockData = [ + { + request: { + query: EVENT_FEEDBACKS, + variables: { + id: 'eventStats123', + }, + }, + result: { + data: { + event: { + _id: 'eventStats123', + feedback: [ + { + _id: 'feedback1', + review: 'review1', + rating: 5, + }, + ], + averageFeedbackScore: 5, + }, + }, + }, + }, +]; + +// Mock the modules for PieChart rendering as they require a trasformer being used (which is not done by Jest) +// These modules are used by the Feedback component +jest.mock('@mui/x-charts/PieChart', () => ({ + pieArcLabelClasses: jest.fn(), + PieChart: jest.fn().mockImplementation(() => <>Test), + pieArcClasses: jest.fn(), +})); + +describe('Testing Event Stats Wrapper', () => { + const props = { + eventId: 'eventStats123', + }; + + test('The button to open and close the modal should work properly', async () => { + const { queryByText, queryByRole } = render( + + + + + , + ); + + // Open the modal + fireEvent.click(queryByText('View Event Statistics') as Element); + + await waitFor(() => + expect(queryByText('Event Statistics')).toBeInTheDocument(), + ); + + // Close the modal + fireEvent.click(queryByRole('button', { name: /close/i }) as HTMLElement); + await waitFor(() => + expect(queryByText('Event Statistics')).not.toBeInTheDocument(), + ); + }); +}); diff --git a/src/components/EventStats/EventStatsWrapper.tsx b/src/components/EventStats/EventStatsWrapper.tsx new file mode 100644 index 0000000000..b501e77430 --- /dev/null +++ b/src/components/EventStats/EventStatsWrapper.tsx @@ -0,0 +1,37 @@ +import React, { useState } from 'react'; +import { EventStats } from './EventStats'; +import { Button } from 'react-bootstrap'; +import IconComponent from 'components/IconComponent/IconComponent'; +import styles from './EventStatsWrapper.module.css'; + +type PropType = { + eventId: string; +}; + +export const EventStatsWrapper = (props: PropType): JSX.Element => { + const [showModal, setShowModal] = useState(false); + + return ( + <> + + setShowModal(false)} + key={props.eventId || 'eventStatsDetails'} + eventId={props.eventId} + /> + + ); +}; diff --git a/src/components/EventStats/Loader.module.css b/src/components/EventStats/Loader.module.css new file mode 100644 index 0000000000..0f78d81c01 --- /dev/null +++ b/src/components/EventStats/Loader.module.css @@ -0,0 +1,43 @@ +.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/components/EventStats/Statistics/AverageRating.test.tsx b/src/components/EventStats/Statistics/AverageRating.test.tsx new file mode 100644 index 0000000000..01cf6461e3 --- /dev/null +++ b/src/components/EventStats/Statistics/AverageRating.test.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { render, waitFor } from '@testing-library/react'; +import { AverageRating } from './AverageRating'; +import { BrowserRouter } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import { I18nextProvider } from 'react-i18next'; +import i18nForTest from 'utils/i18nForTest'; +import { ToastContainer } from 'react-toastify'; + +const props = { + data: { + event: { + _id: '123', + feedback: [ + { + _id: 'feedback1', + review: 'review1', + rating: 5, + }, + { + _id: 'feedback2', + review: 'review2', + rating: 5, + }, + { + _id: 'feedback3', + review: null, + rating: 5, + }, + ], + averageFeedbackScore: 5, + }, + }, +}; + +describe('Testing Average Rating Card', () => { + test('The component should be rendered and the Score should be shown', async () => { + const { queryByText } = render( + + + + + + + + , + ); + + await waitFor(() => + expect(queryByText('Average Review Score')).toBeInTheDocument(), + ); + + await waitFor(() => + expect(queryByText('Rated 5.00 / 5')).toBeInTheDocument(), + ); + }); +}); diff --git a/src/components/EventStats/Statistics/AverageRating.tsx b/src/components/EventStats/Statistics/AverageRating.tsx new file mode 100644 index 0000000000..6dcfa03b3f --- /dev/null +++ b/src/components/EventStats/Statistics/AverageRating.tsx @@ -0,0 +1,57 @@ +import React from 'react'; +import Card from 'react-bootstrap/Card'; +import Rating from '@mui/material/Rating'; +import FavoriteIcon from '@mui/icons-material/Favorite'; +import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder'; +import Typography from '@mui/material/Typography'; + +type ModalPropType = { + data: { + event: { + _id: string; + averageFeedbackScore: number; + feedback: FeedbackType[]; + }; + }; +}; + +type FeedbackType = { + _id: string; + rating: number; + review: string | null; +}; + +export const AverageRating = ({ data }: ModalPropType): JSX.Element => { + return ( + <> + + + +

    Average Review Score

    +
    + + Rated {data.event.averageFeedbackScore.toFixed(2)} / 5 + + } + size="medium" + emptyIcon={} + sx={{ + '& .MuiRating-iconFilled': { + color: '#ff6d75', + }, + '& .MuiRating-iconHover': { + color: '#ff3d47', + }, + }} + /> +
    +
    + + ); +}; diff --git a/src/components/EventStats/Statistics/Feedback.test.tsx b/src/components/EventStats/Statistics/Feedback.test.tsx new file mode 100644 index 0000000000..9abdee4c57 --- /dev/null +++ b/src/components/EventStats/Statistics/Feedback.test.tsx @@ -0,0 +1,104 @@ +import React from 'react'; +import { render, waitFor } from '@testing-library/react'; +import { FeedbackStats } from './Feedback'; +import { BrowserRouter } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import { I18nextProvider } from 'react-i18next'; +import i18nForTest from 'utils/i18nForTest'; +import { ToastContainer } from 'react-toastify'; + +// Mock the modules for PieChart rendering as they require a trasformer being used (which is not done by Jest) +jest.mock('@mui/x-charts/PieChart', () => ({ + pieArcLabelClasses: jest.fn(), + PieChart: jest.fn().mockImplementation(() => <>Test), + pieArcClasses: jest.fn(), +})); + +const nonEmptyProps = { + data: { + event: { + _id: '123', + feedback: [ + { + _id: 'feedback1', + review: 'review1', + rating: 5, + }, + { + _id: 'feedback2', + review: 'review2', + rating: 5, + }, + { + _id: 'feedback3', + review: null, + rating: 5, + }, + ], + averageFeedbackScore: 5, + }, + }, +}; + +const emptyProps = { + data: { + event: { + _id: '123', + feedback: [], + averageFeedbackScore: 5, + }, + }, +}; + +describe('Testing Feedback Statistics Card', () => { + test('The component should be rendered and the feedback should be shown if present', async () => { + const { queryByText } = render( + + + + + + + + , + ); + + await waitFor(() => + expect(queryByText('Feedback Analysis')).toBeInTheDocument(), + ); + + await waitFor(() => + expect( + queryByText('3 people have filled feedback for this event.'), + ).toBeInTheDocument(), + ); + + await waitFor(() => { + expect(queryByText('Test')).toBeInTheDocument(); + }); + }); + + test('The component should be rendered and message should be shown if no feedback is present', async () => { + const { queryByText } = render( + + + + + + + + , + ); + + await waitFor(() => + expect(queryByText('Feedback Analysis')).toBeInTheDocument(), + ); + + await waitFor(() => + expect( + queryByText('Please ask attendees to submit feedback for insights!'), + ).toBeInTheDocument(), + ); + }); +}); diff --git a/src/components/EventStats/Statistics/Feedback.tsx b/src/components/EventStats/Statistics/Feedback.tsx new file mode 100644 index 0000000000..a4a9e41430 --- /dev/null +++ b/src/components/EventStats/Statistics/Feedback.tsx @@ -0,0 +1,103 @@ +import React from 'react'; +import { + PieChart, + pieArcClasses, + pieArcLabelClasses, +} from '@mui/x-charts/PieChart'; +import Card from 'react-bootstrap/Card'; + +type ModalPropType = { + data: { + event: { + _id: string; + averageFeedbackScore: number | null; + feedback: FeedbackType[]; + }; + }; +}; + +type FeedbackType = { + _id: string; + rating: number; + review: string | null; +}; + +export const FeedbackStats = ({ data }: ModalPropType): JSX.Element => { + const ratingColors = [ + '#57bb8a', // Green + '#94bd77', + '#d4c86a', + '#e9b861', + '#e79a69', + '#dd776e', // Red + ]; + + const count: Record = {}; + + data.event.feedback.forEach((feedback: FeedbackType) => { + if (feedback.rating in count) count[feedback.rating]++; + else count[feedback.rating] = 1; + }); + + const chartData = []; + for (let rating = 0; rating <= 5; rating++) { + if (rating in count) + chartData.push({ + id: rating, + value: count[rating], + label: `${rating} (${count[rating]})`, + color: ratingColors[5 - rating], + }); + } + + return ( + <> + + + +

    Feedback Analysis

    +
    +
    + {data.event.feedback.length} people have filled feedback for this + event. +
    + {data.event.feedback.length ? ( + + `${item.id} (${item.value})`, + innerRadius: 30, + outerRadius: 120, + paddingAngle: 2, + cornerRadius: 5, + startAngle: 0, + highlightScope: { faded: 'global', highlighted: 'item' }, + faded: { innerRadius: 30, additionalRadius: -30 }, + }, + ]} + sx={{ + [`& .${pieArcClasses.faded}`]: { + fill: 'gray', + }, + [`& .${pieArcLabelClasses.root}`]: { + fill: 'black', + fontSize: '15px', + }, + [`& .${pieArcLabelClasses.faded}`]: { + display: 'none', + }, + }} + width={380} + height={380} + /> + ) : ( + <>Please ask attendees to submit feedback for insights! + )} +
    +
    + + ); +}; diff --git a/src/components/EventStats/Statistics/Review.test.tsx b/src/components/EventStats/Statistics/Review.test.tsx new file mode 100644 index 0000000000..9093444ab2 --- /dev/null +++ b/src/components/EventStats/Statistics/Review.test.tsx @@ -0,0 +1,95 @@ +import React from 'react'; +import { render, waitFor } from '@testing-library/react'; +import { ReviewStats } from './Review'; +import { BrowserRouter } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import { I18nextProvider } from 'react-i18next'; +import i18nForTest from 'utils/i18nForTest'; +import { ToastContainer } from 'react-toastify'; + +const nonEmptyReviewProps = { + data: { + event: { + _id: '123', + feedback: [ + { + _id: 'feedback1', + review: 'review1', + rating: 5, + }, + { + _id: 'feedback2', + review: 'review2', + rating: 5, + }, + { + _id: 'feedback3', + review: null, + rating: 5, + }, + ], + averageFeedbackScore: 5, + }, + }, +}; + +const emptyReviewProps = { + data: { + event: { + _id: '123', + feedback: [ + { + _id: 'feedback3', + review: null, + rating: 5, + }, + ], + averageFeedbackScore: 5, + }, + }, +}; + +describe('Testing Review Statistics Card', () => { + test('The component should be rendered and the reviews should be shown if present', async () => { + const { queryByText } = render( + + + + + + + + , + ); + + await waitFor(() => expect(queryByText('Reviews')).toBeInTheDocument()); + + await waitFor(() => + expect(queryByText('Filled by 2 people.')).toBeInTheDocument(), + ); + + await waitFor(() => expect(queryByText('review2')).toBeInTheDocument()); + }); + + test('The component should be rendered and message should be shown if no review is present', async () => { + const { queryByText } = render( + + + + + + + + , + ); + + await waitFor(() => expect(queryByText('Reviews')).toBeInTheDocument()); + + await waitFor(() => + expect( + queryByText('Waiting for people to talk about the event...'), + ).toBeInTheDocument(), + ); + }); +}); diff --git a/src/components/EventStats/Statistics/Review.tsx b/src/components/EventStats/Statistics/Review.tsx new file mode 100644 index 0000000000..0afc687023 --- /dev/null +++ b/src/components/EventStats/Statistics/Review.tsx @@ -0,0 +1,57 @@ +import React from 'react'; +import Card from 'react-bootstrap/Card'; +import Rating from '@mui/material/Rating'; + +type ModalPropType = { + data: { + event: { + _id: string; + averageFeedbackScore: number | null; + feedback: FeedbackType[]; + }; + }; +}; + +type FeedbackType = { + _id: string; + rating: number; + review: string | null; +}; + +export const ReviewStats = ({ data }: ModalPropType): JSX.Element => { + const reviews = data.event.feedback.filter( + (feedback: FeedbackType) => feedback.review != null, + ); + + return ( + <> + + + +

    Reviews

    +
    +
    Filled by {reviews.length} people.
    + {reviews.length ? ( + reviews.map((review) => ( +
    +
    + +

    {review.review}

    +
    +
    + )) + ) : ( + <>Waiting for people to talk about the event... + )} +
    +
    + + ); +}; diff --git a/src/components/HolidayCards/HolidayCard.module.css b/src/components/HolidayCards/HolidayCard.module.css new file mode 100644 index 0000000000..c7686ab870 --- /dev/null +++ b/src/components/HolidayCards/HolidayCard.module.css @@ -0,0 +1,12 @@ +.card { + background-color: #b4dcb7; + font-size: 14px; + font-weight: 400; + display: flex; + padding: 8px 4px; + border-radius: 5px; + margin-bottom: 4px; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} diff --git a/src/components/HolidayCards/HolidayCard.tsx b/src/components/HolidayCards/HolidayCard.tsx new file mode 100644 index 0000000000..0235659ee2 --- /dev/null +++ b/src/components/HolidayCards/HolidayCard.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import styles from './HolidayCard.module.css'; + +interface InterfaceHolidayList { + holidayName: string; +} +const HolidayCard = (props: InterfaceHolidayList): JSX.Element => { + /*istanbul ignore next*/ + return
    {props?.holidayName}
    ; +}; + +export default HolidayCard; diff --git a/src/components/IconComponent/IconComponent.test.tsx b/src/components/IconComponent/IconComponent.test.tsx new file mode 100644 index 0000000000..e8faa75404 --- /dev/null +++ b/src/components/IconComponent/IconComponent.test.tsx @@ -0,0 +1,80 @@ +import { render, screen } from '@testing-library/react'; +import IconComponent from './IconComponent'; +import React from 'react'; +const screenTestIdMap: Record> = { + Dashboard: { + name: 'Dashboard', + testId: 'Icon-Component-DashboardIcon', + }, + People: { + name: 'People', + testId: 'Icon-Component-PeopleIcon', + }, + Events: { + name: 'Events', + testId: 'Icon-Component-EventsIcon', + }, + ActionItems: { + name: 'Action Items', + testId: 'Icon-Component-ActionItemIcon', + }, + Posts: { + name: 'Posts', + testId: 'Icon-Component-PostsIcon', + }, + Funds: { + name: 'Funds', + testId: 'Icon-Component-Funds', + }, + BlockUnblock: { + name: 'Block/Unblock', + testId: 'Block/Icon-Component-UnblockIcon', + }, + Plugins: { + name: 'Plugins', + testId: 'Icon-Component-PluginsIcon', + }, + Settings: { + name: 'Settings', + testId: 'Icon-Component-SettingsIcon', + }, + AllOrganizations: { + name: 'My Organizations', + testId: 'Icon-Component-MyOrganizationsIcon', + }, + ListEventRegistrant: { + name: 'List Event Registrants', + testId: 'Icon-Component-List-Event-Registrants', + }, + CheckInRegistrants: { + name: 'Check In Registrants', + testId: 'Icon-Component-Check-In-Registrants', + }, + EventStats: { + name: 'Event Stats', + testId: 'Icon-Component-Event-Stats', + }, + Advertisement: { + name: 'Advertisement', + testId: 'Icon-Component-Advertisement', + }, + Venues: { + name: 'Venues', + testId: 'Icon-Component-Venues', + }, + default: { + name: 'default', + testId: 'Icon-Component-DefaultIcon', + }, +}; + +describe('Testing Collapsible Dropdown component', () => { + it('Renders the correct icon according to the component', () => { + for (const component in screenTestIdMap) { + render(); + expect( + screen.getByTestId(screenTestIdMap[component].testId), + ).toBeInTheDocument(); + } + }); +}); diff --git a/src/components/IconComponent/IconComponent.tsx b/src/components/IconComponent/IconComponent.tsx new file mode 100644 index 0000000000..17f9af8b32 --- /dev/null +++ b/src/components/IconComponent/IconComponent.tsx @@ -0,0 +1,142 @@ +import { QuestionMarkOutlined } from '@mui/icons-material'; +import { ReactComponent as ActionItemIcon } from 'assets/svgs/actionItem.svg'; +import { ReactComponent as AgendaCategoryIcon } from 'assets/svgs/agenda-category-icon.svg'; +import { ReactComponent as BlockUserIcon } from 'assets/svgs/blockUser.svg'; +import { ReactComponent as CheckInRegistrantsIcon } from 'assets/svgs/checkInRegistrants.svg'; +import { ReactComponent as DashboardIcon } from 'assets/svgs/dashboard.svg'; +import { ReactComponent as EventStatsIcon } from 'assets/svgs/eventStats.svg'; +import { ReactComponent as EventsIcon } from 'assets/svgs/events.svg'; +import { ReactComponent as FundsIcon } from 'assets/svgs/funds.svg'; +import { ReactComponent as ListEventRegistrantsIcon } from 'assets/svgs/listEventRegistrants.svg'; +import { ReactComponent as OrganizationsIcon } from 'assets/svgs/organizations.svg'; +import { ReactComponent as PeopleIcon } from 'assets/svgs/people.svg'; +import { ReactComponent as PluginsIcon } from 'assets/svgs/plugins.svg'; +import { ReactComponent as PostsIcon } from 'assets/svgs/posts.svg'; +import { ReactComponent as SettingsIcon } from 'assets/svgs/settings.svg'; +import { ReactComponent as VenueIcon } from 'assets/svgs/venues.svg'; +import { ReactComponent as RequestsIcon } from 'assets/svgs/requests.svg'; +// import { ReactComponent as HomeIcon } from 'assets/svgs/home.svg'; +// import { ReactComponent as DonateIcon } from 'assets/svgs/donate.svg'; + +import React from 'react'; + +export interface InterfaceIconComponent { + name: string; + fill?: string; + height?: string; + width?: string; +} + +const iconComponent = (props: InterfaceIconComponent): JSX.Element => { + switch (props.name) { + case 'My Organizations': + return ( + + ); + case 'Dashboard': + return ( + + ); + case 'People': + return ; + case 'Requests': + return ( + + ); + case 'Events': + return ; + case 'Action Items': + return ( + + ); + case 'Agenda Items Category': + return ( + + ); + case 'Posts': + return ; + case 'Block/Unblock': + return ( + + ); + case 'Plugins': + return ( + + ); + case 'Settings': + return ( + + ); + case 'List Event Registrants': + return ( + + ); + case 'Check In Registrants': + return ( + + ); + case 'Event Stats': + return ( + + ); + case 'Advertisement': + return ( + + ); + case 'Funds': + return ( + + ); + case 'Venues': + return ( + + ); + case 'Home': + return ( + + ); + case 'Donate': + return ( + + ); + default: + return ( + + ); + } +}; + +export default iconComponent; diff --git a/src/components/LeftDrawer/LeftDrawer.module.css b/src/components/LeftDrawer/LeftDrawer.module.css new file mode 100644 index 0000000000..a9d330339f --- /dev/null +++ b/src/components/LeftDrawer/LeftDrawer.module.css @@ -0,0 +1,239 @@ +.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 new file mode 100644 index 0000000000..3873d66dc2 --- /dev/null +++ b/src/components/LeftDrawer/LeftDrawer.test.tsx @@ -0,0 +1,191 @@ +import React 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 { InterfaceLeftDrawerProps } from './LeftDrawer'; +import LeftDrawer from './LeftDrawer'; +import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { MockedProvider } from '@apollo/react-testing'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem } = useLocalStorage(); + +const props = { + hideDrawer: true, + setHideDrawer: jest.fn(), +}; + +const resizeWindow = (width: number): void => { + window.innerWidth = width; + fireEvent(window, new Event('resize')); +}; + +const propsOrg: InterfaceLeftDrawerProps = { + ...props, +}; + +const MOCKS = [ + { + request: { + query: REVOKE_REFRESH_TOKEN, + }, + result: {}, + }, +]; + +const link = new StaticMockLink(MOCKS, true); + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }, +})); + +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('Testing Left Drawer component for SUPERADMIN', () => { + test('Component should be rendered properly', () => { + setItem('UserImage', ''); + setItem('UserImage', ''); + setItem('SuperAdmin', true); + setItem('FirstName', 'John'); + setItem('LastName', 'Doe'); + setItem('UserImage', ''); + setItem('SuperAdmin', true); + setItem('FirstName', 'John'); + setItem('LastName', 'Doe'); + render( + + + + + + + , + ); + + expect(screen.getByText('My Organizations')).toBeInTheDocument(); + expect(screen.getByText('Users')).toBeInTheDocument(); + expect(screen.getByText('Community Profile')).toBeInTheDocument(); + expect(screen.getByText('Community Profile')).toBeInTheDocument(); + expect(screen.getByText('Talawa Admin Portal')).toBeInTheDocument(); + + const orgsBtn = screen.getByTestId(/orgsBtn/i); + const rolesBtn = screen.getByTestId(/rolesBtn/i); + const communityProfileBtn = screen.getByTestId(/communityProfileBtn/i); + + orgsBtn.click(); + expect( + orgsBtn.className.includes('text-white btn btn-success'), + ).toBeTruthy(); + expect(rolesBtn.className.includes('text-secondary btn')).toBeTruthy(); + expect(rolesBtn.className.includes('text-secondary btn')).toBeTruthy(); + expect( + communityProfileBtn.className.includes('text-secondary btn'), + ).toBeTruthy(); + + // Send to roles screen + userEvent.click(rolesBtn); + expect(global.window.location.pathname).toContain('/users'); + userEvent.click(communityProfileBtn); + }); + + test('Testing Drawer when hideDrawer is null', () => { + const tempProps: InterfaceLeftDrawerProps = { + ...props, + hideDrawer: false, + }; + + render( + + + + + + + , + ); + }); + test('Testing Drawer when hideDrawer is false', () => { + const tempProps: InterfaceLeftDrawerProps = { + ...props, + hideDrawer: false, + }; + }); + test('Testing Drawer when the screen size is less than or equal to 820px', () => { + const tempProps: InterfaceLeftDrawerProps = { + ...props, + hideDrawer: false, + }; + resizeWindow(800); + render( + + + + + + + , + ); + expect(screen.getByText('My Organizations')).toBeInTheDocument(); + expect(screen.getByText('Talawa Admin Portal')).toBeInTheDocument(); + + const orgsBtn = screen.getByTestId(/orgsBtn/i); + + orgsBtn.click(); + expect( + orgsBtn.className.includes('text-white btn btn-success'), + ).toBeTruthy(); + }); + + describe('Testing Left Drawer component for ADMIN', () => { + test('Components should be rendered properly', () => { + render( + + + + + + + , + ); + + expect(screen.getByText('My Organizations')).toBeInTheDocument(); + expect(screen.getByText('Talawa Admin Portal')).toBeInTheDocument(); + + expect(screen.getAllByText(/admin/i)).toHaveLength(1); + expect(screen.getAllByText(/admin/i)).toHaveLength(1); + + const orgsBtn = screen.getByTestId(/orgsBtn/i); + orgsBtn.click(); + expect( + orgsBtn.className.includes('text-white btn btn-success'), + ).toBeTruthy(); + + // These screens arent meant for admins so they should not be present + expect(screen.queryByTestId(/rolesBtn/i)).toBeNull(); + + userEvent.click(orgsBtn); + expect(global.window.location.pathname).toContain('/orglist'); + }); + }); +}); diff --git a/src/components/LeftDrawer/LeftDrawer.tsx b/src/components/LeftDrawer/LeftDrawer.tsx new file mode 100644 index 0000000000..dc501d6185 --- /dev/null +++ b/src/components/LeftDrawer/LeftDrawer.tsx @@ -0,0 +1,127 @@ +import React from 'react'; +import Button from 'react-bootstrap/Button'; +import { useTranslation } from 'react-i18next'; +import { NavLink } from 'react-router-dom'; +import { ReactComponent as OrganizationsIcon } from 'assets/svgs/organizations.svg'; +import { ReactComponent as RolesIcon } from 'assets/svgs/roles.svg'; +import { ReactComponent as SettingsIcon } from 'assets/svgs/settings.svg'; +import { ReactComponent as TalawaLogo } from 'assets/svgs/talawa.svg'; +import styles from './LeftDrawer.module.css'; +import useLocalStorage from 'utils/useLocalstorage'; + +export interface InterfaceLeftDrawerProps { + hideDrawer: boolean | null; + setHideDrawer: React.Dispatch>; +} + +const leftDrawer = ({ + hideDrawer, + setHideDrawer, +}: InterfaceLeftDrawerProps): JSX.Element => { + const { t } = useTranslation('translation', { keyPrefix: 'leftDrawer' }); + const { t: tCommon } = useTranslation('common'); + + const { getItem } = useLocalStorage(); + const superAdmin = getItem('SuperAdmin'); + + const handleLinkClick = (): void => { + if (window.innerWidth <= 820) { + setHideDrawer(true); + } + }; + + return ( + <> +
    + +

    {tCommon('talawaAdminPortal')}

    +
    + {tCommon('menu')} +
    +
    + + {({ isActive }) => ( + + )} + + {superAdmin && ( + <> + + {({ isActive }) => ( + + )} + + + {({ isActive }) => ( + + )} + + + )} +
    +
    + + ); +}; + +export default leftDrawer; diff --git a/src/components/LeftDrawerOrg/LeftDrawerOrg.module.css b/src/components/LeftDrawerOrg/LeftDrawerOrg.module.css new file mode 100644 index 0000000000..54560e7969 --- /dev/null +++ b/src/components/LeftDrawerOrg/LeftDrawerOrg.module.css @@ -0,0 +1,350 @@ +.leftDrawer { + width: calc(300px + 2rem); + min-height: 100%; + position: fixed; + top: 0; + bottom: 0; + z-index: 100; + display: flex; + flex-direction: column; + padding: 0.8rem 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 .brandingContainer { + display: flex; + justify-content: flex-start; + align-items: center; +} + +.leftDrawer .organizationContainer button { + position: relative; + margin: 0.7rem 0; + padding: 2.5rem 0.1rem; + border-radius: 16px; +} + +.leftDrawer .talawaLogo { + width: 50px; + height: 50px; + margin-right: 0.3rem; +} + +.leftDrawer .talawaText { + font-size: 18px; + font-weight: 500; +} + +.leftDrawer .titleHeader { + font-weight: 600; + margin: 0.6rem 0rem; +} + +.leftDrawer .optionList { + height: 100%; +} + +.leftDrawer .optionList button { + display: flex; + align-items: center; + width: 100%; + text-align: start; + margin-bottom: 0.8rem; + border-radius: 16px; + font-size: 16px; + padding: 0.6rem; + padding-left: 0.8rem; + outline: none; + border: none; +} + +.leftDrawer button .iconWrapper { + width: 36px; +} + +.leftDrawer .optionList .collapseBtn { + height: 48px; + border: none; +} + +.leftDrawer button .iconWrapperSm { + width: 36px; + display: flex; + justify-content: center; + align-items: center; +} + +.leftDrawer .organizationContainer .profileContainer { + background-color: #31bb6b33; + padding-right: 10px; +} + +.leftDrawer .profileContainer { + border: none; + width: 100%; + height: 52px; + border-radius: 16px; + display: flex; + align-items: center; + background-color: var(--bs-white); +} + +.leftDrawer .profileContainer:focus { + outline: none; +} + +.leftDrawer .imageContainer { + width: 68px; + margin-right: 8px; +} + +.leftDrawer .profileContainer img { + height: 52px; + width: 52px; + border-radius: 50%; +} + +.leftDrawer .profileContainer .profileText { + flex: 1; + text-align: start; + overflow: hidden; +} + +.leftDrawer .profileContainer .profileText .primaryText { + font-size: 1.1rem; + font-weight: 600; + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 2; /* number of lines to show */ + -webkit-box-orient: vertical; + word-wrap: break-word; + white-space: normal; +} + +.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-height: 900px) { + .leftDrawer { + width: calc(300px + 1rem); + } + .leftDrawer .talawaLogo { + width: 38px; + height: 38px; + margin-right: 0.4rem; + } + .leftDrawer .talawaText { + font-size: 1rem; + } + .leftDrawer .organizationContainer button { + margin: 0.6rem 0; + padding: 2.2rem 0.1rem; + } + .leftDrawer .optionList button { + margin-bottom: 0.05rem; + font-size: 16px; + padding-left: 0.8rem; + } + .leftDrawer .profileContainer .profileText .primaryText { + font-size: 1rem; + } + .leftDrawer .profileContainer .profileText .secondaryText { + font-size: 0.8rem; + } +} +@media (max-height: 650px) { + .leftDrawer { + padding: 0.5rem 0.8rem 0 0.8rem; + width: calc(250px); + } + .leftDrawer .talawaText { + font-size: 0.8rem; + } + .leftDrawer .organizationContainer button { + margin: 0.2rem 0; + padding: 1.6rem 0rem; + } + .leftDrawer .titleHeader { + font-size: 16px; + } + .leftDrawer .optionList button { + margin-bottom: 0.05rem; + font-size: 14px; + padding: 0.4rem; + padding-left: 0.8rem; + } + .leftDrawer .profileContainer .profileText .primaryText { + font-size: 0.8rem; + } + .leftDrawer .profileContainer .profileText .secondaryText { + font-size: 0.6rem; + } + .leftDrawer .imageContainer { + width: 40px; + margin-left: 5px; + margin-right: 12px; + } + .leftDrawer .imageContainer img { + width: 40px; + height: 100%; + } +} + +@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.2s ease-in-out; + } + + .activeDrawer { + display: flex; + z-index: 100; + animation: openDrawer 0.4s ease-in-out; + } + + .logout { + margin-bottom: 2.5rem; + } +} + +@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/LeftDrawerOrg/LeftDrawerOrg.test.tsx b/src/components/LeftDrawerOrg/LeftDrawerOrg.test.tsx new file mode 100644 index 0000000000..58a7168552 --- /dev/null +++ b/src/components/LeftDrawerOrg/LeftDrawerOrg.test.tsx @@ -0,0 +1,433 @@ +import React 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 { InterfaceLeftDrawerProps } from './LeftDrawerOrg'; +import LeftDrawerOrg from './LeftDrawerOrg'; +import { Provider } from 'react-redux'; +import { MockedProvider } from '@apollo/react-testing'; +import { store } from 'state/store'; +import { ORGANIZATIONS_LIST } from 'GraphQl/Queries/Queries'; +import { act } from 'react-dom/test-utils'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem } = useLocalStorage(); + +const props: InterfaceLeftDrawerProps = { + orgId: '123', + targets: [ + { + name: 'Dashboard', + url: '/orgdash/123', + }, + { + name: 'People', + url: '/orgpeople/123', + }, + { + name: 'Events', + url: '/orgevents/123', + }, + { + name: 'Posts', + url: '/orgpost/123', + }, + { + name: 'Block/Unblock', + url: '/blockuser/123', + }, + { + name: 'Plugins', + subTargets: [ + { + name: 'Plugin Store', + url: '/orgstore/123', + icon: 'fa-store', + }, + ], + }, + { + name: 'Settings', + url: '/orgsetting/123', + }, + { + name: 'All Organizations', + url: '/orglist/123', + }, + ], + hideDrawer: false, + setHideDrawer: jest.fn(), +}; + +const MOCKS = [ + { + request: { + query: REVOKE_REFRESH_TOKEN, + }, + result: { + data: { + revokeRefreshTokenForUser: true, + }, + }, + }, + { + request: { + query: ORGANIZATIONS_LIST, + variables: { id: '123' }, + }, + result: { + data: { + organizations: [ + { + _id: '123', + image: null, + creator: { + firstName: 'John', + lastName: 'Doe', + email: 'JohnDoe@example.com', + }, + name: 'Test Organization', + description: 'Testing this organization', + address: { + city: 'Delhi', + countryCode: 'IN', + dependentLocality: 'Some Dependent Locality', + line1: '123 Random Street', + line2: 'Apartment 456', + postalCode: '110001', + sortingCode: 'ABC-123', + state: 'Delhi', + }, + userRegistrationRequired: true, + visibleInSearch: true, + members: [ + { + _id: 'john123', + firstName: 'John', + lastName: 'Doe', + email: 'JohnDoe@example.com', + }, + { + _id: 'jane123', + firstName: 'Jane', + lastName: 'Doe', + email: 'JaneDoe@example.com', + }, + ], + admins: [ + { + _id: 'john123', + firstName: 'John', + lastName: 'Doe', + email: 'JohnDoe@example.com', + createdAt: '12-03-2024', + }, + ], + membershipRequests: [], + blockedUsers: [], + }, + ], + }, + }, + }, +]; + +const MOCKS_WITH_IMAGE = [ + { + request: { + query: ORGANIZATIONS_LIST, + variables: { id: '123' }, + }, + result: { + data: { + organizations: [ + { + _id: '123', + image: + 'https://api.dicebear.com/5.x/initials/svg?seed=Test%20Organization', + creator: { + firstName: 'John', + lastName: 'Doe', + email: 'JohnDoe@example.com', + }, + name: 'Test Organization', + description: 'Testing this organization', + address: { + city: 'Delhi', + countryCode: 'IN', + dependentLocality: 'Some Dependent Locality', + line1: '123 Random Street', + line2: 'Apartment 456', + postalCode: '110001', + sortingCode: 'ABC-123', + state: 'Delhi', + }, + userRegistrationRequired: true, + visibleInSearch: true, + members: [ + { + _id: 'john123', + firstName: 'John', + lastName: 'Doe', + email: 'JohnDoe@example.com', + }, + { + _id: 'jane123', + firstName: 'Jane', + lastName: 'Doe', + email: 'JaneDoe@example.com', + }, + ], + admins: [ + { + _id: 'john123', + firstName: 'John', + lastName: 'Doe', + email: 'JohnDoe@example.com', + createdAt: '12-03-2024', + }, + ], + membershipRequests: [], + blockedUsers: [], + }, + ], + }, + }, + }, +]; + +const MOCKS_EMPTY = [ + { + request: { + query: ORGANIZATIONS_LIST, + variables: { id: '123' }, + }, + result: { + data: { + organizations: [], + }, + }, + }, +]; + +const defaultScreens = [ + 'Dashboard', + 'People', + 'Events', + 'Posts', + 'Block/Unblock', + 'Plugins', + 'Settings', + 'All Organizations', +]; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }, +})); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const resizeWindow = (width: number): void => { + window.innerWidth = width; + fireEvent(window, new Event('resize')); +}; + +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(); +}); + +const link = new StaticMockLink(MOCKS, true); +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 () => { + setItem('UserImage', ''); + setItem('SuperAdmin', true); + setItem('FirstName', 'John'); + setItem('LastName', 'Doe'); + render( + + + + + + + + + , + ); + await wait(); + defaultScreens.map((screenName) => { + expect(screen.getByText(screenName)).toBeInTheDocument(); + }); + }); + + test('Testing Profile Page & Organization Detail Modal', async () => { + setItem('UserImage', ''); + setItem('SuperAdmin', true); + setItem('FirstName', 'John'); + setItem('LastName', 'Doe'); + render( + + + + + + + + + , + ); + await wait(); + expect(screen.getByTestId(/orgBtn/i)).toBeInTheDocument(); + }); + + test('Testing Menu Buttons', async () => { + setItem('UserImage', ''); + setItem('SuperAdmin', true); + setItem('FirstName', 'John'); + setItem('LastName', 'Doe'); + render( + + + + + + + + + , + ); + await wait(); + userEvent.click(screen.getByText('Dashboard')); + expect(global.window.location.pathname).toContain('/orgdash/123'); + }); + + test('Testing when screen size is less than 820px', async () => { + setItem('SuperAdmin', true); + render( + + + + + + + + + , + ); + await wait(); + resizeWindow(800); + expect(screen.getByText(/Dashboard/i)).toBeInTheDocument(); + expect(screen.getByText(/People/i)).toBeInTheDocument(); + + const peopelBtn = screen.getByTestId(/People/i); + userEvent.click(peopelBtn); + await wait(); + expect(window.location.pathname).toContain('/orgpeople/123'); + }); + + test('Testing when image is present for Organization', async () => { + setItem('UserImage', ''); + setItem('SuperAdmin', true); + setItem('FirstName', 'John'); + setItem('LastName', 'Doe'); + render( + + + + + + + + + , + ); + await wait(); + }); + + test('Testing when Organization does not exists', async () => { + setItem('UserImage', ''); + setItem('SuperAdmin', true); + setItem('FirstName', 'John'); + setItem('LastName', 'Doe'); + render( + + + + + + + + + , + ); + await wait(); + expect( + screen.getByText(/Error Occured while loading the Organization/i), + ).toBeInTheDocument(); + }); + + test('Testing Drawer when hideDrawer is null', () => { + setItem('UserImage', ''); + setItem('SuperAdmin', true); + setItem('FirstName', 'John'); + setItem('LastName', 'Doe'); + render( + + + + + + + + + , + ); + }); + + test('Testing Drawer when hideDrawer is true', () => { + setItem('UserImage', ''); + setItem('SuperAdmin', true); + setItem('FirstName', 'John'); + setItem('LastName', 'Doe'); + render( + + + + + + + + + , + ); + }); +}); diff --git a/src/components/LeftDrawerOrg/LeftDrawerOrg.tsx b/src/components/LeftDrawerOrg/LeftDrawerOrg.tsx new file mode 100644 index 0000000000..6cc501db45 --- /dev/null +++ b/src/components/LeftDrawerOrg/LeftDrawerOrg.tsx @@ -0,0 +1,173 @@ +import { useQuery } from '@apollo/client'; +import { WarningAmberOutlined } from '@mui/icons-material'; +import { ORGANIZATIONS_LIST } from 'GraphQl/Queries/Queries'; +import CollapsibleDropdown from 'components/CollapsibleDropdown/CollapsibleDropdown'; +import IconComponent from 'components/IconComponent/IconComponent'; +import React, { useEffect, useState } from 'react'; +import Button from 'react-bootstrap/Button'; +import { useTranslation } from 'react-i18next'; +import { NavLink } from 'react-router-dom'; +import type { TargetsType } from 'state/reducers/routesReducer'; +import type { InterfaceQueryOrganizationsListObject } from 'utils/interfaces'; +import { ReactComponent as AngleRightIcon } from 'assets/svgs/angleRight.svg'; +import { ReactComponent as TalawaLogo } from 'assets/svgs/talawa.svg'; +import styles from './LeftDrawerOrg.module.css'; +import Avatar from 'components/Avatar/Avatar'; + +export interface InterfaceLeftDrawerProps { + orgId: string; + targets: TargetsType[]; + hideDrawer: boolean | null; + setHideDrawer: React.Dispatch>; +} + +const leftDrawerOrg = ({ + targets, + orgId, + hideDrawer, + setHideDrawer, +}: InterfaceLeftDrawerProps): JSX.Element => { + const { t: tCommon } = useTranslation('common'); + const [showDropdown, setShowDropdown] = React.useState(false); + + const [organization, setOrganization] = + useState(); + const { + data, + loading, + }: { + data: + | { organizations: InterfaceQueryOrganizationsListObject[] } + | undefined; + loading: boolean; + } = useQuery(ORGANIZATIONS_LIST, { + variables: { id: orgId }, + }); + // Set organization data + useEffect(() => { + let isMounted = true; + if (data && isMounted) { + setOrganization(data?.organizations[0]); + console.log(targets, 'targets'); + } + return () => { + isMounted = false; + }; + }, [data]); + + const handleLinkClick = (): void => { + if (window.innerWidth <= 820) { + setHideDrawer(true); + } + }; + + return ( + <> +
    + {/* Branding Section */} +
    + + + {tCommon('talawaAdminPortal')} + +
    + + {/* Organization Section */} +
    + {loading ? ( + <> + + + ) : ( + + )} +
    + + {/* Options List */} +
    +
    + {tCommon('menu')} +
    + {targets.map(({ name, url }, index) => { + return url ? ( + + {({ isActive }) => ( + + )} + + ) : ( + + ); + })} +
    +
    + + ); +}; + +export default leftDrawerOrg; diff --git a/src/components/Loader/Loader.module.css b/src/components/Loader/Loader.module.css new file mode 100644 index 0000000000..aad512e826 --- /dev/null +++ b/src/components/Loader/Loader.module.css @@ -0,0 +1,25 @@ +.spinner_wrapper { + height: 100vh; + width: 100%; + display: flex; + justify-content: center; + align-items: center; +} + +.spinnerXl { + width: 6rem; + height: 6rem; + border-width: 0.5rem; +} + +.spinnerLg { + height: 4rem; + width: 4rem; + border-width: 0.3rem; +} + +.spinnerSm { + height: 2rem; + width: 2rem; + border-width: 0.2rem; +} diff --git a/src/components/Loader/Loader.test.tsx b/src/components/Loader/Loader.test.tsx new file mode 100644 index 0000000000..c512b480e3 --- /dev/null +++ b/src/components/Loader/Loader.test.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import Loader from './Loader'; + +describe('Testing Loader component', () => { + test('Component should be rendered properly', () => { + render(); + + expect(screen.getByTestId('spinner-wrapper')).toBeInTheDocument(); + expect(screen.getByTestId('spinner')).toBeInTheDocument(); + }); + + test('Component should render on custom sizes', () => { + render(); + + expect(screen.getByTestId('spinner-wrapper')).toBeInTheDocument(); + expect(screen.getByTestId('spinner')).toBeInTheDocument(); + }); + + test('Component should render with large size', () => { + render(); + + expect(screen.getByTestId('spinner-wrapper')).toBeInTheDocument(); + expect(screen.getByTestId('spinner')).toBeInTheDocument(); + }); +}); diff --git a/src/components/Loader/Loader.tsx b/src/components/Loader/Loader.tsx new file mode 100644 index 0000000000..fe5ddef793 --- /dev/null +++ b/src/components/Loader/Loader.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import styles from './Loader.module.css'; +import { Spinner } from 'react-bootstrap'; + +interface InterfaceLoaderProps { + styles?: StyleSheet | string; + size?: 'sm' | 'lg' | 'xl'; +} + +const Loader = (props: InterfaceLoaderProps): JSX.Element => { + return ( + <> +
    + +
    + + ); +}; + +export default Loader; diff --git a/src/components/LoginPortalToggle/LoginPortalToggle.module.css b/src/components/LoginPortalToggle/LoginPortalToggle.module.css new file mode 100644 index 0000000000..5983e20905 --- /dev/null +++ b/src/components/LoginPortalToggle/LoginPortalToggle.module.css @@ -0,0 +1,34 @@ +.navLinkClass { + display: inline-block; + padding: 0.375rem 0.75rem; + font-size: 1rem; + line-height: 1.4; + text-align: center; + vertical-align: middle; + cursor: pointer; + color: var(--bs-gray-900); + border-radius: 0.3rem; + width: 100%; + box-sizing: border-box; + border: 1px solid var(--bs-gray-700); + font-weight: 500; + transition: all 0.25s ease; +} + +.navLinkClass:hover { + color: var(--bs-white); + background-color: var(--bs-gray); + border-color: var(--bs-gray); +} + +.activeLink { + color: var(--bs-white); + border: 1px solid var(--bs-primary); + background-color: var(--bs-primary); +} + +.activeLink:hover { + color: var(--bs-white); + background-color: var(--bs-primary); + border: 1px solid var(--bs-primary); +} diff --git a/src/components/LoginPortalToggle/LoginPortalToggle.test.tsx b/src/components/LoginPortalToggle/LoginPortalToggle.test.tsx new file mode 100644 index 0000000000..ac971e52ea --- /dev/null +++ b/src/components/LoginPortalToggle/LoginPortalToggle.test.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { act, render } from '@testing-library/react'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { I18nextProvider } from 'react-i18next'; +import LoginPortalToggle from './LoginPortalToggle'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +describe('Testing LoginPortalToggle component', () => { + test('Component Should be rendered properly', async () => { + const mockOnToggle = jest.fn(); + render( + + + + + + + , + ); + + await wait(); + }); +}); diff --git a/src/components/LoginPortalToggle/LoginPortalToggle.tsx b/src/components/LoginPortalToggle/LoginPortalToggle.tsx new file mode 100644 index 0000000000..c1feb9f4da --- /dev/null +++ b/src/components/LoginPortalToggle/LoginPortalToggle.tsx @@ -0,0 +1,47 @@ +import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import styles from './LoginPortalToggle.module.css'; +import Col from 'react-bootstrap/Col'; +import Row from 'react-bootstrap/Row'; +import { NavLink } from 'react-router-dom'; + +interface InterfaceLoginPortalToggleProps { + onToggle: (role: 'admin' | 'user') => void; +} + +function loginPortalToggle({ + onToggle, +}: InterfaceLoginPortalToggleProps): JSX.Element { + const { t: tCommon } = useTranslation('common'); + const [activeRole, setActiveRole] = useState<'admin' | 'user'>('admin'); + + const handleNavLinkClick = (role: 'admin' | 'user'): void => { + onToggle(role); + setActiveRole(role); + }; + + return ( + + + handleNavLinkClick('admin')} + > + {tCommon('admin')} + + + + handleNavLinkClick('user')} + > + {tCommon('user')} + + + + ); +} + +export default loginPortalToggle; diff --git a/src/components/MemberRequestCard/MemberRequestCard.module.css b/src/components/MemberRequestCard/MemberRequestCard.module.css new file mode 100644 index 0000000000..fdc99eba83 --- /dev/null +++ b/src/components/MemberRequestCard/MemberRequestCard.module.css @@ -0,0 +1,57 @@ +.memberlist { + margin-top: -1px; +} +.memberimg { + border-radius: 10px; + margin-left: 10px; +} +.singledetails { + display: flex; + flex-direction: row; + justify-content: space-between; +} +.singledetails p { + margin-bottom: -5px; +} +.singledetails_data_left { + margin-top: 10px; + margin-left: 10px; + color: #707070; +} +.singledetails_data_right { + justify-content: right; + margin-top: 10px; + text-align: right; + color: #707070; +} +.membername { + font-size: 16px; + font-weight: bold; +} +.memberfont { + margin-top: 3px; +} +.memberfont > span { + width: 80%; +} +.memberfontcreated { + margin-top: 18px; +} +.memberfontcreatedbtn { + margin-top: 33px; + border-radius: 7px; + border-color: #e8e5e5; + background-color: #f7f7f7; + padding-right: 10px; + padding-left: 10px; + justify-content: flex-end; + float: right; + text-align: right; + box-shadow: none; +} +#grid_wrapper { + align-items: left; +} +.peoplelistdiv { + margin-right: 50px; +} diff --git a/src/components/MemberRequestCard/MemberRequestCard.test.tsx b/src/components/MemberRequestCard/MemberRequestCard.test.tsx new file mode 100644 index 0000000000..121213e4e7 --- /dev/null +++ b/src/components/MemberRequestCard/MemberRequestCard.test.tsx @@ -0,0 +1,122 @@ +import React from 'react'; +import { act, render, screen } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import userEvent from '@testing-library/user-event'; +import { I18nextProvider } from 'react-i18next'; + +import { + ACCEPT_ORGANIZATION_REQUEST_MUTATION, + REJECT_ORGANIZATION_REQUEST_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import MemberRequestCard from './MemberRequestCard'; +import i18nForTest from 'utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; + +const MOCKS = [ + { + request: { + query: ACCEPT_ORGANIZATION_REQUEST_MUTATION, + variable: { id: '123' }, + }, + result: { + data: { + organizations: [ + { + _id: '1', + }, + ], + }, + }, + }, + { + request: { + query: REJECT_ORGANIZATION_REQUEST_MUTATION, + variable: { id: '234' }, + }, + result: { + data: { + organizations: [ + { + _id: '2', + }, + ], + }, + }, + }, +]; +const link = new StaticMockLink(MOCKS, true); +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +describe('Testing Member Request Card', () => { + const props = { + key: '123', + id: '1', + memberName: 'John Doe', + memberLocation: 'India', + joinDate: '18/03/2022', + memberImage: 'image', + email: 'johndoe@gmail.com', + }; + + global.alert = jest.fn(); + + it('should render props and text elements test for the page component', async () => { + global.confirm = (): boolean => true; + + render( + + + + + , + ); + + await wait(); + userEvent.click(screen.getByText(/Accept/i)); + userEvent.click(screen.getByText(/Reject/i)); + + expect(screen.getByAltText(/userImage/i)).toBeInTheDocument(); + expect(screen.getByText(/Joined:/i)).toBeInTheDocument(); + expect(screen.getByText(props.memberName)).toBeInTheDocument(); + expect(screen.getByText(props.memberLocation)).toBeInTheDocument(); + expect(screen.getByText(props.joinDate)).toBeInTheDocument(); + expect(screen.getByText(props.email)).toBeInTheDocument(); + }); + + it('Should render text elements when props value is not passed', async () => { + global.confirm = (): boolean => false; + + render( + + + + + , + ); + + await wait(); + userEvent.click(screen.getByText(/Accept/i)); + userEvent.click(screen.getByText(/Reject/i)); + + expect(screen.getByAltText(/userImage/i)).toBeInTheDocument(); + expect(screen.getByText(/Joined:/i)).toBeInTheDocument(); + expect(screen.queryByText(props.memberName)).not.toBeInTheDocument(); + expect(screen.getByText(props.memberLocation)).toBeInTheDocument(); + expect(screen.getByText(props.joinDate)).toBeInTheDocument(); + expect(screen.getByText(props.email)).toBeInTheDocument(); + }); +}); diff --git a/src/components/MemberRequestCard/MemberRequestCard.tsx b/src/components/MemberRequestCard/MemberRequestCard.tsx new file mode 100644 index 0000000000..462e78d2ee --- /dev/null +++ b/src/components/MemberRequestCard/MemberRequestCard.tsx @@ -0,0 +1,126 @@ +import React from 'react'; +import styles from './MemberRequestCard.module.css'; +import Row from 'react-bootstrap/Row'; +import Col from 'react-bootstrap/Col'; +import Button from 'react-bootstrap/Button'; +import { useMutation } from '@apollo/client'; +import { + ACCEPT_ORGANIZATION_REQUEST_MUTATION, + REJECT_ORGANIZATION_REQUEST_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; +import defaultImg from 'assets/images/blank.png'; +import { errorHandler } from 'utils/errorHandler'; + +interface InterfaceMemberRequestCardProps { + key: string; + id: string; + memberName: string; + memberLocation: string; + joinDate: string; + memberImage: string; + email: string; +} + +function memberRequestCard( + props: InterfaceMemberRequestCardProps, +): JSX.Element { + const [acceptMutation] = useMutation(ACCEPT_ORGANIZATION_REQUEST_MUTATION); + const [rejectMutation] = useMutation(REJECT_ORGANIZATION_REQUEST_MUTATION); + + const { t } = useTranslation('translation', { + keyPrefix: 'membershipRequest', + }); + const { t: tCommon } = useTranslation('common'); + + const addMember = async (): Promise => { + try { + await acceptMutation({ + variables: { + id: props.id, + }, + }); + + /* istanbul ignore next */ + toast.success(t('memberAdded')); + /* istanbul ignore next */ + setTimeout(() => { + window.location.reload(); + }, 2000); + } catch (error: unknown) { + /* istanbul ignore next */ + errorHandler(t, error); + } + }; + + const rejectMember = async (): Promise => { + const sure = window.confirm('Are you sure you want to Reject Request ?'); + if (sure) { + try { + await rejectMutation({ + variables: { + userid: props.id, + }, + }); + + /* istanbul ignore next */ + window.location.reload(); + } catch (error: unknown) { + /* istanbul ignore next */ + errorHandler(t, error); + } + } + }; + + return ( + <> +
    + + {props.memberImage ? ( + userImage + ) : ( + userImage + )} + +
    +

    + {props.memberName ? <>{props.memberName} : <>Dogs Care} +

    +

    {props.memberLocation}

    +

    {props.email}

    +
    +
    +

    + {tCommon('joined')}: {props.joinDate} +

    + + +
    + +
    +
    +
    + + ); +} +export {}; +export default memberRequestCard; diff --git a/src/components/NotFound/NotFound.module.css b/src/components/NotFound/NotFound.module.css new file mode 100644 index 0000000000..a209bc9f48 --- /dev/null +++ b/src/components/NotFound/NotFound.module.css @@ -0,0 +1,22 @@ +.section { + flex: 1; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.error { + font-size: 1.2rem; + font-weight: 500; +} + +@media (min-width: 440px) and (max-width: 570px) { + .section { + margin-left: 50px; + } + .error { + font-size: 1.1rem; + font-style: oblique; + } +} diff --git a/src/components/NotFound/NotFound.test.tsx b/src/components/NotFound/NotFound.test.tsx new file mode 100644 index 0000000000..54c0bcfe4a --- /dev/null +++ b/src/components/NotFound/NotFound.test.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { I18nextProvider } from 'react-i18next'; +import i18nForTest from 'utils/i18nForTest'; + +import { render, screen } from '@testing-library/react'; +import NotFound from './NotFound'; + +describe('Tesing the NotFound Component', () => { + it('renders the component with the correct title for posts', () => { + render( + + + , + ); + expect(screen.getByText(/Not Found!/i)).toBeInTheDocument(); + }); + + it('renders the component with the correct title for users', () => { + render( + + + , + ); + expect(screen.getByText(/Not Found!/i)).toBeInTheDocument(); + }); +}); diff --git a/src/components/NotFound/NotFound.tsx b/src/components/NotFound/NotFound.tsx new file mode 100644 index 0000000000..6e2853cf82 --- /dev/null +++ b/src/components/NotFound/NotFound.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; + +import styles from './NotFound.module.css'; + +interface InterfaceNotFoundProps { + title: string; + keyPrefix: string; +} + +function notFound(props: InterfaceNotFoundProps): JSX.Element { + const key = props.keyPrefix.toString(); + const { t } = useTranslation('translation', { + keyPrefix: key, + }); + return ( + <> +
    +

    {t(`${props.title} not found!`)}

    +
    + + ); +} + +export default notFound; diff --git a/src/components/OrgActionItemCategories/OrgActionItemCategories.module.css b/src/components/OrgActionItemCategories/OrgActionItemCategories.module.css new file mode 100644 index 0000000000..ac9f4a5900 --- /dev/null +++ b/src/components/OrgActionItemCategories/OrgActionItemCategories.module.css @@ -0,0 +1,33 @@ +.addButton { + width: 7em; + position: absolute; + right: 1rem; + top: 1rem; +} + +.createModal { + margin-top: 20vh; + margin-left: 13vw; + max-width: 80vw; +} + +.icon { + transform: scale(1.5); + color: var(--bs-danger); + margin-bottom: 1rem; +} + +.message { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.titlemodal { + color: var(--bs-gray-600); + font-weight: 600; + font-size: 20px; + margin-top: 1rem; + width: 65%; +} diff --git a/src/components/OrgActionItemCategories/OrgActionItemCategories.test.tsx b/src/components/OrgActionItemCategories/OrgActionItemCategories.test.tsx new file mode 100644 index 0000000000..0665ce6fc4 --- /dev/null +++ b/src/components/OrgActionItemCategories/OrgActionItemCategories.test.tsx @@ -0,0 +1,372 @@ +import React from 'react'; +import { + render, + screen, + fireEvent, + waitFor, + act, +} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import 'jest-localstorage-mock'; +import { MockedProvider } from '@apollo/client/testing'; +import 'jest-location-mock'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import i18n from 'utils/i18nForTest'; +import { toast } from 'react-toastify'; + +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; + +import OrgActionItemCategories from './OrgActionItemCategories'; +import { + MOCKS, + MOCKS_ERROR_QUERY, + MOCKS_ERROR_MUTATIONS, +} from './OrgActionItemCategoryMocks'; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: '123' }), +})); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(MOCKS_ERROR_QUERY, true); +const link3 = new StaticMockLink(MOCKS_ERROR_MUTATIONS, true); + +const translations = { + ...JSON.parse( + JSON.stringify( + i18n.getDataByLanguage('en')?.translation.orgActionItemCategories ?? {}, + ), + ), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), +}; + +describe('Testing Action Item Categories Component', () => { + test('Component loads correctly', async () => { + window.location.assign('/orgsetting/123'); + const { getByText } = render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(getByText(translations.create)).toBeInTheDocument(); + }); + }); + + test('render error component on unsuccessful query', async () => { + window.location.assign('/orgsetting/123'); + const { queryByText } = render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(queryByText(translations.create)).not.toBeInTheDocument(); + }); + }); + + test('opens and closes create and update modals on button clicks', async () => { + window.location.assign('/orgsetting/123'); + render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + userEvent.click(screen.getByTestId('actionItemCategoryModalOpenBtn')); + userEvent.click(screen.getByTestId('actionItemCategoryModalCloseBtn')); + }); + + await waitFor(() => { + userEvent.click( + screen.getAllByTestId('actionItemCategoryUpdateModalOpenBtn')[0], + ); + userEvent.click(screen.getByTestId('actionItemCategoryModalCloseBtn')); + }); + }); + + test('create a new action item category', async () => { + window.location.assign('/orgsetting/123'); + render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + userEvent.click(screen.getByTestId('actionItemCategoryModalOpenBtn')); + userEvent.type( + screen.getByPlaceholderText(translations.enterName), + 'ActionItemCategory 4', + ); + + userEvent.click(screen.getByTestId('formSubmitButton')); + }); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.successfulCreation); + }); + }); + + test('toast error on unsuccessful creation', async () => { + window.location.assign('/orgsetting/123'); + render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + userEvent.click(screen.getByTestId('actionItemCategoryModalOpenBtn')); + userEvent.type( + screen.getByPlaceholderText(translations.enterName), + 'ActionItemCategory 4', + ); + + userEvent.click(screen.getByTestId('formSubmitButton')); + }); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); + + test('update an action item category', async () => { + window.location.assign('/orgsetting/123'); + render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + userEvent.click( + screen.getAllByTestId('actionItemCategoryUpdateModalOpenBtn')[0], + ); + + const name = screen.getByPlaceholderText(translations.enterName); + fireEvent.change(name, { target: { value: '' } }); + + userEvent.type( + screen.getByPlaceholderText(translations.enterName), + 'ActionItemCategory 1 updated', + ); + + userEvent.click(screen.getByTestId('formSubmitButton')); + }); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.successfulUpdation); + }); + }); + + test('toast error on unsuccessful updation', async () => { + window.location.assign('/orgsetting/123'); + render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + userEvent.click( + screen.getAllByTestId('actionItemCategoryUpdateModalOpenBtn')[0], + ); + + const name = screen.getByPlaceholderText(translations.enterName); + fireEvent.change(name, { target: { value: '' } }); + + userEvent.type( + screen.getByPlaceholderText(translations.enterName), + 'ActionItemCategory 1 updated', + ); + + userEvent.click(screen.getByTestId('formSubmitButton')); + }); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); + + test('toast error on providing the same name on updation', async () => { + window.location.assign('/orgsetting/123'); + render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + userEvent.click( + screen.getAllByTestId('actionItemCategoryUpdateModalOpenBtn')[0], + ); + + const name = screen.getByPlaceholderText(translations.enterName); + fireEvent.change(name, { target: { value: '' } }); + + userEvent.type( + screen.getByPlaceholderText(translations.enterName), + 'ActionItemCategory 1', + ); + + userEvent.click(screen.getByTestId('formSubmitButton')); + }); + + await waitFor(() => { + expect(toast.error).toBeCalledWith(translations.sameNameConflict); + }); + }); + + test('toggle the disablity status of an action item category', async () => { + window.location.assign('/orgsetting/123'); + render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + userEvent.click(screen.getAllByTestId('disabilityStatusButton')[0]); + }); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.categoryDisabled); + }); + + await waitFor(() => { + userEvent.click(screen.getAllByTestId('disabilityStatusButton')[1]); + }); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.categoryEnabled); + }); + }); + + test('toast error on unsuccessful toggling of the disablity status', async () => { + window.location.assign('/orgsetting/123'); + render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + userEvent.click(screen.getAllByTestId('disabilityStatusButton')[0]); + }); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + + await waitFor(() => { + userEvent.click(screen.getAllByTestId('disabilityStatusButton')[1]); + }); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/components/OrgActionItemCategories/OrgActionItemCategories.tsx b/src/components/OrgActionItemCategories/OrgActionItemCategories.tsx new file mode 100644 index 0000000000..f893319e38 --- /dev/null +++ b/src/components/OrgActionItemCategories/OrgActionItemCategories.tsx @@ -0,0 +1,292 @@ +import type { ChangeEvent } from 'react'; +import React, { useState } from 'react'; +import { Button, Form, Modal } from 'react-bootstrap'; +import styles from './OrgActionItemCategories.module.css'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; +import { WarningAmberRounded } from '@mui/icons-material'; + +import { useMutation, useQuery } from '@apollo/client'; +import { + CREATE_ACTION_ITEM_CATEGORY_MUTATION, + UPDATE_ACTION_ITEM_CATEGORY_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import { ACTION_ITEM_CATEGORY_LIST } from 'GraphQl/Queries/Queries'; +import type { InterfaceActionItemCategoryList } from 'utils/interfaces'; +import Loader from 'components/Loader/Loader'; +import { useParams } from 'react-router-dom'; + +type ModalType = 'Create' | 'Update'; + +const OrgActionItemCategories = (): JSX.Element => { + const { t } = useTranslation('translation', { + keyPrefix: 'orgActionItemCategories', + }); + const { t: tCommon } = useTranslation('common'); + + const [modalIsOpen, setModalIsOpen] = useState(false); + const [modalType, setModalType] = useState('Create'); + const [categoryId, setCategoryId] = useState(''); + + const [name, setName] = useState(''); + const [currName, setCurrName] = useState(''); + + const { orgId: currentUrl } = useParams(); + + const { + data, + loading, + error, + refetch, + }: { + data: InterfaceActionItemCategoryList | undefined; + loading: boolean; + error?: Error | undefined; + refetch: () => void; + } = useQuery(ACTION_ITEM_CATEGORY_LIST, { + variables: { + organizationId: currentUrl, + }, + notifyOnNetworkStatusChange: true, + }); + + const [createActionItemCategory] = useMutation( + CREATE_ACTION_ITEM_CATEGORY_MUTATION, + ); + + const [updateActionItemCategory] = useMutation( + UPDATE_ACTION_ITEM_CATEGORY_MUTATION, + ); + + const handleCreate = async ( + e: ChangeEvent, + ): Promise => { + e.preventDefault(); + try { + await createActionItemCategory({ + variables: { + name, + organizationId: currentUrl, + }, + }); + + setName(''); + refetch(); + + setModalIsOpen(false); + + toast.success(t('successfulCreation')); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + console.log(error.message); + } + } + }; + + const handleEdit = async (e: ChangeEvent): Promise => { + e.preventDefault(); + if (name === currName) { + toast.error(t('sameNameConflict')); + } else { + try { + await updateActionItemCategory({ + variables: { + actionItemCategoryId: categoryId, + name, + }, + }); + + setName(''); + setCategoryId(''); + refetch(); + + setModalIsOpen(false); + + toast.success(t('successfulUpdation')); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + console.log(error.message); + } + } + } + }; + + const handleStatusChange = async ( + id: string, + disabledStatus: boolean, + ): Promise => { + try { + await updateActionItemCategory({ + variables: { + actionItemCategoryId: id, + isDisabled: !disabledStatus, + }, + }); + + refetch(); + + toast.success( + disabledStatus ? t('categoryEnabled') : t('categoryDisabled'), + ); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + console.log(error.message); + } + } + }; + + const showCreateModal = (): void => { + setModalType('Create'); + setModalIsOpen(true); + }; + + const showUpdateModal = (name: string, id: string): void => { + setCurrName(name); + setName(name); + setCategoryId(id); + setModalType('Update'); + setModalIsOpen(true); + }; + + const hideModal = (): void => { + setName(''); + setCategoryId(''); + setModalIsOpen(false); + }; + + if (loading) { + return ; + } + + if (error) { + return ( +
    + +
    + Error occured while loading Action Item Categories Data +
    + {`${error.message}`} +
    +
    + ); + } + + const actionItemCategories = data?.actionItemCategoriesByOrganization; + + return ( + <> + + +
    + {actionItemCategories?.map((category, index) => { + return ( +
    +
    +
    + {category.name} +
    +
    + + +
    +
    + + {index !== actionItemCategories.length - 1 &&
    } +
    + ); + })} +
    + + + +

    + {t('actionItemCategoryDetails')} +

    + +
    + +
    + + {t('actionItemCategoryName')} + + { + setName(e.target.value); + }} + /> + + +
    +
    + + ); +}; + +export default OrgActionItemCategories; diff --git a/src/components/OrgActionItemCategories/OrgActionItemCategoryMocks.ts b/src/components/OrgActionItemCategories/OrgActionItemCategoryMocks.ts new file mode 100644 index 0000000000..b03e53c5f5 --- /dev/null +++ b/src/components/OrgActionItemCategories/OrgActionItemCategoryMocks.ts @@ -0,0 +1,174 @@ +import { + CREATE_ACTION_ITEM_CATEGORY_MUTATION, + UPDATE_ACTION_ITEM_CATEGORY_MUTATION, +} from 'GraphQl/Mutations/mutations'; + +import { ACTION_ITEM_CATEGORY_LIST } from 'GraphQl/Queries/Queries'; + +export const MOCKS = [ + { + request: { + query: ACTION_ITEM_CATEGORY_LIST, + variables: { organizationId: '123' }, + }, + result: { + data: { + actionItemCategoriesByOrganization: [ + { + _id: '1', + name: 'ActionItemCategory 1', + isDisabled: false, + }, + { + _id: '2', + name: 'ActionItemCategory 2', + isDisabled: true, + }, + { + _id: '3', + name: 'ActionItemCategory 3', + isDisabled: false, + }, + ], + }, + }, + }, + { + request: { + query: CREATE_ACTION_ITEM_CATEGORY_MUTATION, + variables: { name: 'ActionItemCategory 4', organizationId: '123' }, + }, + result: { + data: { + createActionItemCategory: { + _id: '4', + }, + }, + }, + }, + { + request: { + query: UPDATE_ACTION_ITEM_CATEGORY_MUTATION, + variables: { + name: 'ActionItemCategory 1 updated', + actionItemCategoryId: '1', + }, + }, + result: { + data: { + updateActionItemCategory: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: UPDATE_ACTION_ITEM_CATEGORY_MUTATION, + variables: { + isDisabled: true, + actionItemCategoryId: '1', + }, + }, + result: { + data: { + updateActionItemCategory: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: UPDATE_ACTION_ITEM_CATEGORY_MUTATION, + variables: { + isDisabled: false, + actionItemCategoryId: '2', + }, + }, + result: { + data: { + updateActionItemCategory: { + _id: '2', + }, + }, + }, + }, +]; + +export const MOCKS_ERROR_QUERY = [ + { + request: { + query: ACTION_ITEM_CATEGORY_LIST, + variables: { organizationId: '123' }, + }, + error: new Error('Mock Graphql Error'), + }, +]; + +export const MOCKS_ERROR_MUTATIONS = [ + { + request: { + query: ACTION_ITEM_CATEGORY_LIST, + variables: { organizationId: '123' }, + }, + result: { + data: { + actionItemCategoriesByOrganization: [ + { + _id: '1', + name: 'ActionItemCategory 1', + isDisabled: false, + }, + { + _id: '2', + name: 'ActionItemCategory 2', + isDisabled: true, + }, + { + _id: '3', + name: 'ActionItemCategory 3', + isDisabled: false, + }, + ], + }, + }, + }, + { + request: { + query: CREATE_ACTION_ITEM_CATEGORY_MUTATION, + variables: { name: 'ActionItemCategory 4', organizationId: '123' }, + }, + error: new Error('Mock Graphql Error'), + }, + { + request: { + query: UPDATE_ACTION_ITEM_CATEGORY_MUTATION, + variables: { + name: 'ActionItemCategory 1 updated', + actionItemCategoryId: '1', + }, + }, + error: new Error('Mock Graphql Error'), + }, + { + request: { + query: UPDATE_ACTION_ITEM_CATEGORY_MUTATION, + variables: { + isDisabled: true, + actionItemCategoryId: '1', + }, + }, + error: new Error('Mock Graphql Error'), + }, + { + request: { + query: UPDATE_ACTION_ITEM_CATEGORY_MUTATION, + variables: { + isDisabled: false, + actionItemCategoryId: '2', + }, + }, + error: new Error('Mock Graphql Error'), + }, +]; diff --git a/src/components/OrgAdminListCard/OrgAdminListCard.test.tsx b/src/components/OrgAdminListCard/OrgAdminListCard.test.tsx new file mode 100644 index 0000000000..282dedb330 --- /dev/null +++ b/src/components/OrgAdminListCard/OrgAdminListCard.test.tsx @@ -0,0 +1,108 @@ +import React from 'react'; +import { act, render, screen, waitFor } from '@testing-library/react'; +import type { RenderResult } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import userEvent from '@testing-library/user-event'; +import { I18nextProvider } from 'react-i18next'; +import { REMOVE_ADMIN_MUTATION } from 'GraphQl/Mutations/mutations'; +import OrgAdminListCard from './OrgAdminListCard'; +import i18nForTest from 'utils/i18nForTest'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; +import { StaticMockLink } from 'utils/StaticMockLink'; + +const MOCKS = [ + { + request: { + query: REMOVE_ADMIN_MUTATION, + variables: { userid: '456', orgid: '987' }, + }, + result: { + data: { + removeAdmin: { + _id: '456', + }, + }, + }, + }, +]; +const link = new StaticMockLink(MOCKS, true); +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const renderOrgAdminListCard = (props: { + toggleRemoveModal: () => boolean; + id: string | undefined; +}): RenderResult => { + return render( + + + + + } + /> + orgListScreen} + /> + + + + , + ); +}; +jest.mock('i18next-browser-languagedetector', () => ({ + init: jest.fn(), + type: 'languageDetector', + detect: jest.fn(() => 'en'), + cacheUserLanguage: jest.fn(), +})); +describe('Testing Organization Admin List Card', () => { + global.alert = jest.fn(); + + beforeEach(() => { + Object.defineProperty(window, 'location', { + writable: true, + value: { reload: jest.fn() }, + }); + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + + test('should render props and text elements test for the page component', async () => { + const props = { + toggleRemoveModal: () => true, + id: '456', + }; + + renderOrgAdminListCard(props); + + await wait(); + + userEvent.click(screen.getByTestId(/removeAdminBtn/i)); + + await wait(2000); + }); + + test('Should not render text elements when props value is not passed', async () => { + const props = { + toggleRemoveModal: () => true, + id: undefined, + }; + + renderOrgAdminListCard(props); + + await waitFor(() => { + const orgListScreen = screen.getByTestId('orgListScreen'); + expect(orgListScreen).toBeInTheDocument(); + }); + }); +}); diff --git a/src/components/OrgAdminListCard/OrgAdminListCard.tsx b/src/components/OrgAdminListCard/OrgAdminListCard.tsx new file mode 100644 index 0000000000..9afb47000d --- /dev/null +++ b/src/components/OrgAdminListCard/OrgAdminListCard.tsx @@ -0,0 +1,73 @@ +import React from 'react'; +import Button from 'react-bootstrap/Button'; +import Modal from 'react-bootstrap/Modal'; +import { useMutation } from '@apollo/client'; +import { toast } from 'react-toastify'; +import { REMOVE_ADMIN_MUTATION } from 'GraphQl/Mutations/mutations'; +import { useTranslation } from 'react-i18next'; +import { Navigate, useParams } from 'react-router-dom'; +import { errorHandler } from 'utils/errorHandler'; + +interface InterfaceOrgPeopleListCardProps { + id: string | undefined; + toggleRemoveModal: () => void; +} + +function orgAdminListCard(props: InterfaceOrgPeopleListCardProps): JSX.Element { + if (!props.id) { + return ; + } + const { orgId: currentUrl } = useParams(); + const [remove] = useMutation(REMOVE_ADMIN_MUTATION); + + const { t } = useTranslation('translation', { + keyPrefix: 'orgAdminListCard', + }); + const { t: tCommon } = useTranslation('common'); + + const removeAdmin = async (): Promise => { + try { + const { data } = await remove({ + variables: { + userid: props.id, + orgid: currentUrl, + }, + }); + if (data) { + toast.success(t('adminRemoved')); + setTimeout(() => { + window.location.reload(); + }, 2000); + } + } catch (error: unknown) { + /* istanbul ignore next */ + errorHandler(t, error); + } + }; + return ( + <> + + +
    {t('removeAdmin')}
    + +
    + {t('removeAdminMsg')} + + + + +
    + + ); +} +export default orgAdminListCard; diff --git a/src/components/OrgContriCards/OrgContriCards.module.css b/src/components/OrgContriCards/OrgContriCards.module.css new file mode 100644 index 0000000000..d20b696621 --- /dev/null +++ b/src/components/OrgContriCards/OrgContriCards.module.css @@ -0,0 +1,22 @@ +.cards { + width: 45%; + background: #fcfcfc; + margin: 10px 20px; + padding: 20px 30px; + border-radius: 5px; + border: 1px solid #e8e8e8; + box-shadow: 0 3px 5px #c9c9c9; + margin-right: 40px; + color: #737373; +} +.cards > h2 { + font-size: 19px; +} +.cards > h3 { + font-size: 17px; +} +.cards > p { + font-size: 14px; + margin-top: -5px; + margin-bottom: 7px; +} diff --git a/src/components/OrgContriCards/OrgContriCards.test.tsx b/src/components/OrgContriCards/OrgContriCards.test.tsx new file mode 100644 index 0000000000..4f202cd355 --- /dev/null +++ b/src/components/OrgContriCards/OrgContriCards.test.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import type { NormalizedCacheObject } from '@apollo/client'; +import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client'; +import { I18nextProvider } from 'react-i18next'; + +import OrgContriCards from './OrgContriCards'; +import i18nForTest from 'utils/i18nForTest'; +import { BACKEND_URL } from 'Constant/constant'; + +const client: ApolloClient = new ApolloClient({ + cache: new InMemoryCache(), + uri: BACKEND_URL, +}); + +describe('Testing the Organization Contributions Cards', () => { + const props = { + key: '123', + id: '123', + userName: 'John Doe', + contriDate: '06/03/2022', + contriAmount: '500', + contriTransactionId: 'QW56DA88', + userEmail: 'johndoe@gmail.com', + }; + + it('should render props and text elements test for the page component', () => { + render( + + + + + , + ); + expect(screen.getByText('Date:')).toBeInTheDocument(); + expect(screen.getByText('John Doe')).toBeInTheDocument(); + expect(screen.getByText('06/03/2022')).toBeInTheDocument(); + expect(screen.getByText('500')).toBeInTheDocument(); + expect(screen.getByText('QW56DA88')).toBeInTheDocument(); + expect(screen.getByText('johndoe@gmail.com')).toBeInTheDocument(); + }); +}); diff --git a/src/components/OrgContriCards/OrgContriCards.tsx b/src/components/OrgContriCards/OrgContriCards.tsx new file mode 100644 index 0000000000..69a9e03d58 --- /dev/null +++ b/src/components/OrgContriCards/OrgContriCards.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import Row from 'react-bootstrap/Row'; +import Col from 'react-bootstrap/Col'; +import { useTranslation } from 'react-i18next'; + +import styles from './OrgContriCards.module.css'; + +interface InterfaceOrgContriCardsProps { + key: string; + id: string; + userName: string; + contriDate: string; + contriAmount: string; + contriTransactionId: string; + userEmail: string; +} +function orgContriCards(props: InterfaceOrgContriCardsProps): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'orgContriCards', + }); + + return ( + <> + + +

    {props.userName}

    +

    {props.userEmail}

    +

    + {t('date')}:{props.contriDate} +

    +

    + {t('transactionId')}: {props.contriTransactionId} +

    +

    + {t('amount')}: $ {props.contriAmount} +

    + +
    + + ); +} +export default orgContriCards; diff --git a/src/components/OrgDelete/OrgDelete.test.tsx b/src/components/OrgDelete/OrgDelete.test.tsx new file mode 100644 index 0000000000..b9b9ca2572 --- /dev/null +++ b/src/components/OrgDelete/OrgDelete.test.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import type { NormalizedCacheObject } from '@apollo/client'; +import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client'; +import { I18nextProvider } from 'react-i18next'; + +import OrgDelete from './OrgDelete'; +import i18nForTest from 'utils/i18nForTest'; +import { BACKEND_URL } from 'Constant/constant'; + +const client: ApolloClient = new ApolloClient({ + cache: new InMemoryCache(), + uri: BACKEND_URL, +}); + +describe('Testing Organization People List Card', () => { + test('should render props and text elements test for the page component', () => { + render( + + + + + , + ); + expect(screen.getByText('Delete Org')).toBeInTheDocument(); + }); +}); diff --git a/src/components/OrgDelete/OrgDelete.tsx b/src/components/OrgDelete/OrgDelete.tsx new file mode 100644 index 0000000000..0f1335dae4 --- /dev/null +++ b/src/components/OrgDelete/OrgDelete.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; + +function orgDelete(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'orgDelete', + }); + + return ( + <> +
    + {t('deleteOrg')} +
    + + ); +} +export default orgDelete; diff --git a/src/components/OrgListCard/OrgListCard.module.css b/src/components/OrgListCard/OrgListCard.module.css new file mode 100644 index 0000000000..430ea318d6 --- /dev/null +++ b/src/components/OrgListCard/OrgListCard.module.css @@ -0,0 +1,141 @@ +.orgCard { + 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; +} + +.orgCard .innerContainer { + display: flex; +} + +.orgCard .innerContainer .orgImgContainer { + display: flex; + justify-content: center; + align-items: center; + position: relative; + overflow: hidden; + border-radius: 4px; +} + +.orgCard .innerContainer .orgImgContainer { + width: 125px; + height: 120px; + object-fit: contain; +} + +.orgCard .innerContainer .orgImgContainer { + width: 125px; + height: 120px; + background-color: var(--bs-gray-200); +} + +.orgCard .innerContainer .content { + flex: 1; + margin-left: 1rem; + width: 70%; + margin-top: 0.7rem; +} + +.orgCard button { + position: absolute; + bottom: 1rem; + right: 1rem; + z-index: 1; +} + +.flaskIcon { + margin-top: 4px; +} + +.manageBtn { + display: flex; + justify-content: space-around; + width: 8rem; +} + +.orgName { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + font-size: 1rem; +} + +.orgdesc { + font-size: 0.9rem; + color: var(--bs-gray-600); + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 1; + line-clamp: 1; + -webkit-box-orient: vertical; + max-width: 20rem; +} + +.orgadmin { + font-size: 0.9rem; +} + +.orgmember { + font-size: 0.9rem; +} + +.address { + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 1; + line-clamp: 1; + -webkit-box-orient: vertical; + align-items: center; +} + +.address h6 { + font-size: 0.9rem; + color: var(--bs-gray-600); +} + +@media (max-width: 580px) { + .orgCard { + height: unset; + margin: 0.5rem 0; + padding: 1.25rem 1.5rem; + } + + .orgCard .innerContainer { + flex-direction: column; + } + + .orgCard .innerContainer .orgImgContainer { + margin-bottom: 0.8rem; + } + + .orgCard .innerContainer .orgImgContainer img { + height: auto; + width: 100%; + } + + .orgCard .innerContainer .content { + margin-left: 0; + } + + .orgCard button { + bottom: 0; + right: 0; + position: relative; + margin-left: auto; + display: block; + } + + .flaskIcon { + margin-bottom: 6px; + } + + .manageBtn { + display: flex; + justify-content: space-around; + width: 100%; + } +} diff --git a/src/components/OrgListCard/OrgListCard.test.tsx b/src/components/OrgListCard/OrgListCard.test.tsx new file mode 100644 index 0000000000..25d7f01ed1 --- /dev/null +++ b/src/components/OrgListCard/OrgListCard.test.tsx @@ -0,0 +1,149 @@ +import React from 'react'; +import { act, render, screen } from '@testing-library/react'; +import 'jest-location-mock'; +import { I18nextProvider } from 'react-i18next'; + +import i18nForTest from 'utils/i18nForTest'; +import type { InterfaceOrgListCardProps } from './OrgListCard'; +import OrgListCard from './OrgListCard'; +import userEvent from '@testing-library/user-event'; +import { BrowserRouter } from 'react-router-dom'; +import { IS_SAMPLE_ORGANIZATION_QUERY } from 'GraphQl/Queries/Queries'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { MockedProvider } from '@apollo/react-testing'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem, removeItem } = useLocalStorage(); + +const MOCKS = [ + { + request: { + query: IS_SAMPLE_ORGANIZATION_QUERY, + variables: { + isSampleOrganizationId: 'xyz', + }, + }, + result: { + data: { + isSampleOrganization: true, + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const props: InterfaceOrgListCardProps = { + data: { + _id: 'xyz', + name: 'Dogs Care', + image: 'https://api.dicebear.com/5.x/initials/svg?seed=John%20Doe', + address: { + city: 'Sample City', + countryCode: 'US', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Sample Street', + line2: 'Apartment 456', + postalCode: '12345', + sortingCode: 'ABC-123', + state: 'Sample State', + }, + admins: [ + { + _id: '123', + }, + { + _id: '456', + }, + ], + members: [], + createdAt: '04/07/2019', + creator: { + _id: 'abc', + firstName: 'John', + lastName: 'Doe', + }, + }, +}; + +describe('Testing the Super Dash List', () => { + test('should render props and text elements test for the page component', async () => { + removeItem('id'); + setItem('id', '123'); // Means the user is an admin + + render( + + + + + + + , + ); + await wait(); + expect(screen.getByAltText(/Dogs Care image/i)).toBeInTheDocument(); + expect(screen.getByText(/Admins:/i)).toBeInTheDocument(); + expect(screen.getByText(/Members:/i)).toBeInTheDocument(); + expect(screen.getByText('Dogs Care')).toBeInTheDocument(); + expect(screen.getByText(/Sample City/i)).toBeInTheDocument(); + expect(screen.getByText(/123 Sample Street/i)).toBeInTheDocument(); + expect(screen.getByTestId(/manageBtn/i)).toBeInTheDocument(); + expect(screen.getByTestId(/flaskIcon/i)).toBeInTheDocument(); + userEvent.click(screen.getByTestId(/manageBtn/i)); + removeItem('id'); + }); + + test('Testing if the props data is not provided', () => { + window.location.assign('/orgdash'); + + render( + + + + + + + , + ); + + expect(window.location).toBeAt('/orgdash'); + }); + + test('Testing if component is rendered properly when image is null', () => { + const imageNullProps = { + ...props, + ...{ data: { ...props.data, ...{ image: null } } }, + }; + render( + + + + + + + , + ); + expect(screen.getByTestId(/emptyContainerForImage/i)).toBeInTheDocument(); + }); + + test('Testing if user is redirected to orgDash screen', () => { + render( + + + + + + + , + ); + userEvent.click(screen.getByTestId('manageBtn')); + }); +}); diff --git a/src/components/OrgListCard/OrgListCard.tsx b/src/components/OrgListCard/OrgListCard.tsx new file mode 100644 index 0000000000..bdba9107b0 --- /dev/null +++ b/src/components/OrgListCard/OrgListCard.tsx @@ -0,0 +1,113 @@ +import React from 'react'; +import { ReactComponent as FlaskIcon } from 'assets/svgs/flask.svg'; +import Button from 'react-bootstrap/Button'; +import { useTranslation } from 'react-i18next'; +import styles from './OrgListCard.module.css'; +import { useNavigate } from 'react-router-dom'; +import type { + InterfaceOrgConnectionInfoType, + InterfaceQueryOrganizationsListObject, +} from 'utils/interfaces'; +import { + IS_SAMPLE_ORGANIZATION_QUERY, + ORGANIZATIONS_LIST, +} from 'GraphQl/Queries/Queries'; +import { useQuery } from '@apollo/client'; +import { Tooltip } from '@mui/material'; +import Avatar from 'components/Avatar/Avatar'; + +export interface InterfaceOrgListCardProps { + data: InterfaceOrgConnectionInfoType; +} + +function orgListCard(props: InterfaceOrgListCardProps): JSX.Element { + const { _id, admins, image, address, members, name } = props.data; + + const { data } = useQuery(IS_SAMPLE_ORGANIZATION_QUERY, { + variables: { + isSampleOrganizationId: _id, + }, + }); + + const navigate = useNavigate(); + const { + data: userData, + }: { + data?: { + organizations: InterfaceQueryOrganizationsListObject[]; + }; + } = useQuery(ORGANIZATIONS_LIST, { + variables: { id: _id }, + }); + + function handleClick(): void { + const url = '/orgdash/' + _id; + + // Dont change the below two lines + navigate(url); + } + + const { t } = useTranslation('translation', { + keyPrefix: 'orgListCard', + }); + const { t: tCommon } = useTranslation('common'); + + return ( + <> +
    +
    +
    + {image ? ( + {`${name} + ) : ( + + )} +
    +
    + +

    {name}

    +
    +
    + {userData?.organizations[0].description} +
    + {address && address.city && ( +
    +
    + {address.line1}, + {address.city}, + {address.countryCode} +
    +
    + )} +
    + {tCommon('admins')}: {admins.length}     +   {tCommon('members')}: {members.length} +
    +
    +
    + +
    + + ); +} +export default orgListCard; diff --git a/src/components/OrgPeopleListCard/OrgPeopleListCard.test.tsx b/src/components/OrgPeopleListCard/OrgPeopleListCard.test.tsx new file mode 100644 index 0000000000..57a6e0265f --- /dev/null +++ b/src/components/OrgPeopleListCard/OrgPeopleListCard.test.tsx @@ -0,0 +1,81 @@ +import React from 'react'; +import { act, render, screen } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import userEvent from '@testing-library/user-event'; +import { I18nextProvider } from 'react-i18next'; + +import OrgPeopleListCard from './OrgPeopleListCard'; +import { REMOVE_MEMBER_MUTATION } from 'GraphQl/Mutations/mutations'; +import i18nForTest from 'utils/i18nForTest'; +import { BrowserRouter } from 'react-router-dom'; +import { StaticMockLink } from 'utils/StaticMockLink'; + +const MOCKS = [ + { + request: { + query: REMOVE_MEMBER_MUTATION, + variable: { userid: '123', orgid: '456' }, + }, + result: { + data: { + organizations: [ + { + _id: '1', + }, + ], + }, + }, + }, +]; +const link = new StaticMockLink(MOCKS, true); +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +describe('Testing Organization People List Card', () => { + const props = { + toggleRemoveModal: () => true, + id: '1', + }; + global.alert = jest.fn(); + + test('should render props and text elements test for the page component', async () => { + global.confirm = (): boolean => true; + + render( + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId(/removeMemberBtn/i)); + }); + + test('Should not render modal when id is undefined', async () => { + global.confirm = (): boolean => false; + + render( + + + + true} /> + + + , + ); + + await wait(); + + expect(window.location.pathname).toEqual('/orglist'); + }); +}); diff --git a/src/components/OrgPeopleListCard/OrgPeopleListCard.tsx b/src/components/OrgPeopleListCard/OrgPeopleListCard.tsx new file mode 100644 index 0000000000..781443847b --- /dev/null +++ b/src/components/OrgPeopleListCard/OrgPeopleListCard.tsx @@ -0,0 +1,79 @@ +import React from 'react'; +import Button from 'react-bootstrap/Button'; +import Modal from 'react-bootstrap/Modal'; +import { useMutation } from '@apollo/client'; +import { toast } from 'react-toastify'; +import { useTranslation } from 'react-i18next'; +import { REMOVE_MEMBER_MUTATION } from 'GraphQl/Mutations/mutations'; +import { useParams, Navigate } from 'react-router-dom'; +import { errorHandler } from 'utils/errorHandler'; + +interface InterfaceOrgPeopleListCardProps { + id: string | undefined; + toggleRemoveModal: () => void; +} + +function orgPeopleListCard( + props: InterfaceOrgPeopleListCardProps, +): JSX.Element { + const { orgId: currentUrl } = useParams(); + if (!props.id) { + return ; + } + const [remove] = useMutation(REMOVE_MEMBER_MUTATION); + + const { t } = useTranslation('translation', { + keyPrefix: 'orgPeopleListCard', + }); + const { t: tCommon } = useTranslation('common'); + + const removeMember = async (): Promise => { + try { + const { data } = await remove({ + variables: { + userid: props.id, + orgid: currentUrl, + }, + }); + + /* istanbul ignore next */ + if (data) { + toast.success(t('memberRemoved')); + setTimeout(() => { + window.location.reload(); + }, 2000); + } + } catch (error: unknown) { + /* istanbul ignore next */ + errorHandler(t, error); + } + }; + return ( +
    + + +
    {t('removeMember')}
    + +
    + {t('removeMemberMsg')} + + + + +
    +
    + ); +} +export {}; +export default orgPeopleListCard; diff --git a/src/components/OrgPostCard/OrgPostCard.module.css b/src/components/OrgPostCard/OrgPostCard.module.css new file mode 100644 index 0000000000..c7ff8073d2 --- /dev/null +++ b/src/components/OrgPostCard/OrgPostCard.module.css @@ -0,0 +1,278 @@ +.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; +} +.nopostimage { + 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; +} +.author { + color: #737373; + font-weight: 100; + font-size: 13px; +} +.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 a { + color: #737373; + font-weight: 600; +} +.cards a:hover { + color: black; +} +.infodiv { + margin-bottom: 7px; + width: 15rem; + text-align: justify; + word-wrap: break-word; +} +.infodiv > p { + margin: 0; +} +.dispflex { + display: flex; + justify-content: space-between; +} +.iconContainer { + display: flex; +} +.icon { + transform: scale(0.75); + cursor: pointer; +} +/* .cards { + width: 75%; + background: #fcfcfc; + margin: 10px 40px; + padding: 20px 30px; + border-radius: 5px; + border: 1px solid #e8e8e8; + box-shadow: 0 3px 5px #c9c9c9; + margin-right: 30px; + color: #737373; + box-sizing: border-box; +} */ +.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; +} +.toggleClickBtn { + color: #31bb6b; + cursor: pointer; + border: none; + font-size: 12px; + background-color: white; +} +.toggleClickBtnNone { + display: none; +} +/* Menu Modal Styles */ +.menuModal { + 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.7); /* Dark grey modal background */ + z-index: 9999; +} + +.menuContent { + display: flex; + align-items: center; + justify-content: center; + background-color: #fff; + padding-top: 20px; + max-width: 700px; + max-height: 500px; + overflow: hidden; + position: relative; +} + +.menuOptions { + list-style-type: none; + padding: 0; + margin: 0; +} + +.menuOptions li { + padding: 10px; + border-bottom: 1px solid #ccc; + padding-left: 100px; + padding-right: 100px; + cursor: pointer; +} + +.moreOptionsButton { + position: relative; + bottom: 5rem; + right: 10px; + padding: 2px; + background-color: transparent; + color: #000; + border: none; + cursor: pointer; +} +.list { + color: red; + cursor: pointer; +} diff --git a/src/components/OrgPostCard/OrgPostCard.test.tsx b/src/components/OrgPostCard/OrgPostCard.test.tsx new file mode 100644 index 0000000000..863ed2822b --- /dev/null +++ b/src/components/OrgPostCard/OrgPostCard.test.tsx @@ -0,0 +1,599 @@ +import React from 'react'; +import { + act, + render, + screen, + fireEvent, + waitFor, +} from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import OrgPostCard from './OrgPostCard'; +import { I18nextProvider } from 'react-i18next'; +import userEvent from '@testing-library/user-event'; +import 'jest-localstorage-mock'; +import { + DELETE_POST_MUTATION, + UPDATE_POST_MUTATION, + TOGGLE_PINNED_POST, +} from 'GraphQl/Mutations/mutations'; +import i18nForTest from 'utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import convertToBase64 from 'utils/convertToBase64'; +import { BrowserRouter } from 'react-router-dom'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem } = useLocalStorage(); + +const MOCKS = [ + { + request: { + query: DELETE_POST_MUTATION, + variables: { id: '12' }, + }, + result: { + data: { + removePost: { + _id: '12', + }, + }, + }, + }, + { + request: { + query: UPDATE_POST_MUTATION, + variables: { + id: '12', + title: 'updated title', + text: 'This is a updated text', + }, + }, + result: { + data: { + updatePost: { + _id: '12', + }, + }, + }, + }, + { + request: { + query: TOGGLE_PINNED_POST, + variables: { + id: '12', + }, + }, + result: { + data: { + togglePostPin: { + _id: '12', + }, + }, + }, + }, +]; +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }, +})); +jest.mock('i18next-browser-languagedetector', () => ({ + init: jest.fn(), + type: 'languageDetector', + detect: jest.fn(() => 'en'), + cacheUserLanguage: jest.fn(), +})); +const link = new StaticMockLink(MOCKS, true); +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} +describe('Testing Organization Post Card', () => { + const originalLocation = window.location; + + beforeAll(() => { + Object.defineProperty(window, 'location', { + configurable: true, + value: { + reload: jest.fn(), + }, + }); + }); + + afterAll(() => { + Object.defineProperty(window, 'location', { + configurable: true, + value: originalLocation, + }); + }); + + const props = { + key: '123', + id: '12', + postTitle: 'Event Info', + postInfo: 'Time change', + postAuthor: 'John Doe', + postPhoto: 'test.png', + postVideo: 'test.mp4', + pinned: false, + }; + + jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }, + })); + jest.mock('react', () => ({ + ...jest.requireActual('react'), + useRef: jest.fn(), + })); + global.alert = jest.fn(); + + test('renders with default props', () => { + const { getByAltText, getByTestId } = render( + + + + + , + ); + expect(getByTestId('card-text')).toBeInTheDocument(); + expect(getByTestId('card-title')).toBeInTheDocument(); + expect(getByAltText('image')).toBeInTheDocument(); + }); + + test('toggles "Read more" button', () => { + const { getByTestId } = render( + + + + + , + ); + userEvent.click(screen.getByAltText('image')); + const toggleButton = getByTestId('toggleBtn'); + fireEvent.click(toggleButton); + expect(toggleButton).toHaveTextContent('hide'); + fireEvent.click(toggleButton); + expect(toggleButton).toHaveTextContent('Read more'); + }); + test('opens and closes edit modal', async () => { + setItem('id', '123'); + + render( + + + + + , + ); + await wait(); + userEvent.click(screen.getByAltText('image')); + userEvent.click(screen.getByTestId('moreiconbtn')); + userEvent.click(screen.getByTestId('editPostModalBtn')); + + const createOrgBtn = screen.getByTestId('modalOrganizationHeader'); + expect(createOrgBtn).toBeInTheDocument(); + userEvent.click(createOrgBtn); + userEvent.click(screen.getByTestId('closeOrganizationModal')); + }); + test('Should render text elements when props value is not passed', async () => { + global.confirm = (): boolean => false; + render( + + + + + , + ); + await wait(); + userEvent.click(screen.getByAltText('image')); + expect(screen.getByAltText('Post Image')).toBeInTheDocument(); + }); + test('Testing post updating after post is updated', async () => { + const { getByTestId } = render( + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByAltText('image')); + userEvent.click(screen.getByTestId('moreiconbtn')); + + userEvent.click(screen.getByTestId('editPostModalBtn')); + fireEvent.change(getByTestId('updateTitle'), { + target: { value: 'updated title' }, + }); + fireEvent.change(getByTestId('updateText'), { + target: { value: 'This is a updated text' }, + }); + const postVideoUrlInput = screen.queryByTestId('postVideoUrl'); + if (postVideoUrlInput) { + fireEvent.change(getByTestId('postVideoUrl'), { + target: { value: 'This is a updated video' }, + }); + userEvent.click(screen.getByPlaceholderText(/video/i)); + const input = getByTestId('postVideoUrl'); + const file = new File(['test-video'], 'test.mp4', { type: 'video/mp4' }); + Object.defineProperty(input, 'files', { + value: [file], + }); + fireEvent.change(input); + await waitFor(() => { + convertToBase64(file); + }); + + userEvent.click(screen.getByTestId('closePreview')); + } + const imageUrlInput = screen.queryByTestId('postImageUrl'); + if (imageUrlInput) { + fireEvent.change(getByTestId('postImageUrl'), { + target: { value: 'This is a updated image' }, + }); + userEvent.click(screen.getByPlaceholderText(/image/i)); + const input = getByTestId('postImageUrl'); + const file = new File(['test-image'], 'test.jpg', { type: 'image/jpeg' }); + Object.defineProperty(input, 'files', { + value: [file], + }); + fireEvent.change(input); + + // Simulate the asynchronous base64 conversion function + await waitFor(() => { + convertToBase64(file); // Replace with the expected base64-encoded image + }); + document.getElementById = jest.fn(() => input); + const clearImageButton = getByTestId('closeimage'); + fireEvent.click(clearImageButton); + } + userEvent.click(screen.getByTestId('updatePostBtn')); + + await waitFor( + () => { + expect(window.location.reload).toHaveBeenCalled(); + }, + { timeout: 2500 }, + ); + }); + test('Testing pin post functionality', async () => { + render( + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByAltText('image')); + userEvent.click(screen.getByTestId('moreiconbtn')); + userEvent.click(screen.getByTestId('pinpostBtn')); + + await waitFor( + () => { + expect(window.location.reload).toHaveBeenCalled(); + }, + { timeout: 3000 }, + ); + }); + test('Testing pin post functionality fail case', async () => { + const props2 = { + key: '123', + id: '', + postTitle: 'Event Info', + postInfo: 'Time change', + postAuthor: 'John Doe', + postPhoto: 'test.png', + postVideo: 'test.mp4', + pinned: true, + }; + render( + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByAltText('image')); + userEvent.click(screen.getByTestId('moreiconbtn')); + userEvent.click(screen.getByTestId('pinpostBtn')); + }); + test('Testing post delete functionality', async () => { + render( + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByAltText('image')); + userEvent.click(screen.getByTestId('moreiconbtn')); + + userEvent.click(screen.getByTestId('deletePostModalBtn')); + fireEvent.click(screen.getByTestId('deletePostBtn')); + + await waitFor( + () => { + expect(window.location.reload).toHaveBeenCalled(); + }, + { timeout: 3000 }, + ); + }); + test('Testing post delete functionality fail case', async () => { + const props2 = { + key: '123', + id: '', + postTitle: 'Event Info', + postInfo: 'Time change', + postAuthor: 'John Doe', + postPhoto: 'test.png', + postVideo: 'test.mp4', + pinned: true, + }; + render( + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByAltText('image')); + userEvent.click(screen.getByTestId('moreiconbtn')); + + userEvent.click(screen.getByTestId('deletePostModalBtn')); + fireEvent.click(screen.getByTestId('deletePostBtn')); + }); + test('Testing close functionality of primary modal', async () => { + render( + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByAltText('image')); + userEvent.click(screen.getByTestId('closeiconbtn')); + }); + test('Testing close functionality of secondary modal', async () => { + render( + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByAltText('image')); + userEvent.click(screen.getByTestId('moreiconbtn')); + userEvent.click(screen.getByTestId('closebtn')); + }); + test('renders without "Read more" button when postInfo length is less than or equal to 43', () => { + const props2 = { + key: '123', + id: '12', + postTitle: 'Event Info', + postInfo: 'Lorem ipsum dolor sit amet', + postAuthor: 'John Doe', + postPhoto: 'photoLink', + postVideo: 'videoLink', + pinned: false, + }; + render( + + + + + , + ); + }); + test('updates state variables correctly when handleEditModal is called', () => { + const link2 = new StaticMockLink(MOCKS, true); + render( + + + , + ); + userEvent.click(screen.getByAltText('image')); + + userEvent.click(screen.getByTestId('moreiconbtn')); + + expect(screen.queryByTestId('editPostModalBtn')).toBeInTheDocument(); + + userEvent.click(screen.getByTestId('editPostModalBtn')); + + // expect(screen.queryByTestId('editPostModalBtn')).toBeInTheDocument(); + // expect(screen.queryByTestId('deletePostModalBtn')).not.toBeInTheDocument(); + // expect(screen.queryByTestId('closeiconbtn')).not.toBeInTheDocument(); + + // expect(screen.getByTestId('editPostModal')).toHaveClass('show'); + // expect(screen.getByTestId('deletePostModal')).not.toHaveClass('show'); + + // expect(screen.getByTestId('modalVisible')).toBe('false'); + // expect(screen.getByTestId('menuVisible')).toBe('false'); + // expect(screen.getByTestId('showEditModal')).toBe('true'); + // expect(screen.getByTestId('showDeleteModal')).toBe('false'); + }); + test('clears postvideo state and resets file input value', async () => { + const { getByTestId } = render( + + + + + , + ); + + userEvent.click(screen.getByAltText('image')); + userEvent.click(screen.getByTestId('moreiconbtn')); + + userEvent.click(screen.getByTestId('editPostModalBtn')); + + const postVideoUrlInput = screen.queryByTestId('postVideoUrl'); + + if (postVideoUrlInput) { + fireEvent.change(getByTestId('postVideoUrl'), { + target: { value: '' }, + }); + userEvent.click(screen.getByPlaceholderText(/video/i)); + const input = getByTestId('postVideoUrl'); + const file = new File(['test-video'], 'test.mp4', { type: 'video/mp4' }); + Object.defineProperty(input, 'files', { + value: [file], + }); + fireEvent.change(input); + await waitFor(() => { + convertToBase64(file); + }); + + userEvent.click(screen.getByTestId('closePreview')); + } + }); + test('clears postimage state and resets file input value', async () => { + const { getByTestId } = render( + + + + + , + ); + + userEvent.click(screen.getByAltText('image')); + userEvent.click(screen.getByTestId('moreiconbtn')); + + userEvent.click(screen.getByTestId('editPostModalBtn')); + + const imageUrlInput = screen.queryByTestId('postImageUrl'); + + if (imageUrlInput) { + fireEvent.change(getByTestId('postImageUrl'), { + target: { value: '' }, + }); + userEvent.click(screen.getByPlaceholderText(/image/i)); + const input = getByTestId('postImageUrl'); + const file = new File(['test-image'], 'test.jpg', { type: 'image/jpeg' }); + Object.defineProperty(input, 'files', { + value: [file], + }); + fireEvent.change(input); + + // Simulate the asynchronous base64 conversion function + await waitFor(() => { + convertToBase64(file); // Replace with the expected base64-encoded image + }); + document.getElementById = jest.fn(() => input); + const clearImageButton = getByTestId('closeimage'); + fireEvent.click(clearImageButton); + } + }); + test('Testing create organization modal', async () => { + setItem('id', '123'); + + render( + + + + + , + ); + + await wait(); + userEvent.click(screen.getByAltText('image')); + + userEvent.click(screen.getByTestId('moreiconbtn')); + + userEvent.click(screen.getByTestId('editPostModalBtn')); + const createOrgBtn = screen.getByTestId('modalOrganizationHeader'); + expect(createOrgBtn).toBeInTheDocument(); + userEvent.click(createOrgBtn); + userEvent.click(screen.getByTestId('closeOrganizationModal')); + }); + test('should toggle post pin when pin button is clicked', async () => { + const { getByTestId } = render( + + + + + , + ); + userEvent.click(screen.getByAltText('image')); + + userEvent.click(screen.getByTestId('moreiconbtn')); + const pinButton = getByTestId('pinpostBtn'); + fireEvent.click(pinButton); + await waitFor(() => { + expect(MOCKS[2].request.variables).toEqual({ + id: '12', + }); + }); + }); + test('testing video play and pause on mouse enter and leave events', async () => { + const { getByTestId } = render( + + + + + , + ); + + const card = getByTestId('cardVid'); + + HTMLVideoElement.prototype.play = jest.fn(); + HTMLVideoElement.prototype.pause = jest.fn(); + + fireEvent.mouseEnter(card); + expect(HTMLVideoElement.prototype.play).toHaveBeenCalled(); + + fireEvent.mouseLeave(card); + expect(HTMLVideoElement.prototype.pause).toHaveBeenCalled(); + }); + test('for rendering when no image and no video is available', async () => { + const props2 = { + key: '123', + id: '', + postTitle: 'Event Info', + postInfo: 'Time change', + postAuthor: 'John Doe', + postPhoto: '', + postVideo: '', + pinned: true, + }; + + const { getByAltText } = render( + + + + + , + ); + + expect(getByAltText('image not found')).toBeInTheDocument(); + }); +}); diff --git a/src/components/OrgPostCard/OrgPostCard.tsx b/src/components/OrgPostCard/OrgPostCard.tsx new file mode 100644 index 0000000000..be71622c7c --- /dev/null +++ b/src/components/OrgPostCard/OrgPostCard.tsx @@ -0,0 +1,601 @@ +import { useMutation } from '@apollo/client'; +import { Close, MoreVert, PushPin } from '@mui/icons-material'; +import { + DELETE_POST_MUTATION, + TOGGLE_PINNED_POST, + UPDATE_POST_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import AboutImg from 'assets/images/defaultImg.png'; +import type { ChangeEvent } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; +import { Form, Button, Card, Modal } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; +import convertToBase64 from 'utils/convertToBase64'; +import { errorHandler } from 'utils/errorHandler'; +import type { InterfacePostForm } from 'utils/interfaces'; +import styles from './OrgPostCard.module.css'; +interface InterfaceOrgPostCardProps { + key: string; + id: string; + postTitle: string; + postInfo: string; + postAuthor: string; + postPhoto: string | null; + postVideo: string | null; + pinned: boolean; +} +export default function orgPostCard( + props: InterfaceOrgPostCardProps, +): JSX.Element { + const [postformState, setPostFormState] = useState({ + posttitle: '', + postinfo: '', + postphoto: '', + postvideo: '', + pinned: false, + }); + const [postPhotoUpdated, setPostPhotoUpdated] = useState(false); + const [postVideoUpdated, setPostVideoUpdated] = useState(false); + const [togglePost, setPostToggle] = useState('Read more'); + const [showEditModal, setShowEditModal] = useState(false); + const [showDeleteModal, setShowDeleteModal] = useState(false); + const [modalVisible, setModalVisible] = useState(false); + const [menuVisible, setMenuVisible] = useState(false); + const [playing, setPlaying] = useState(false); + const videoRef = useRef(null); + const [toggle] = useMutation(TOGGLE_PINNED_POST); + const togglePostPin = async (id: string, pinned: boolean): Promise => { + try { + const { data } = await toggle({ + variables: { + id, + }, + }); + if (data) { + setModalVisible(false); + setMenuVisible(false); + toast.success(`${pinned ? 'Post unpinned' : 'Post pinned'}`); + setTimeout(() => { + window.location.reload(); + }, 2000); + } + } catch (error: unknown) { + if (error instanceof Error) { + /* istanbul ignore next */ + errorHandler(t, error); + } + } + }; + const toggleShowEditModal = (): void => { + setPostFormState({ + posttitle: props.postTitle, + postinfo: props.postInfo, + postphoto: props.postPhoto, + postvideo: props.postVideo, + pinned: props.pinned, + }); + setPostPhotoUpdated(false); + setPostVideoUpdated(false); + setShowEditModal((prev) => !prev); + }; + const toggleShowDeleteModal = (): void => setShowDeleteModal((prev) => !prev); + const handleVideoPlay = (): void => { + setPlaying(true); + videoRef.current?.play(); + }; + const handleVideoPause = (): void => { + setPlaying(false); + videoRef.current?.pause(); + }; + const handleCardClick = (): void => { + setModalVisible(true); + }; + const handleMoreOptionsClick = (): void => { + setMenuVisible(true); + }; + const clearImageInput = (): void => { + setPostFormState({ + ...postformState, + postphoto: '', + }); + setPostPhotoUpdated(true); + const fileInput = document.getElementById( + 'postImageUrl', + ) as HTMLInputElement; + if (fileInput) { + fileInput.value = ''; + } + }; + const clearVideoInput = (): void => { + setPostFormState({ + ...postformState, + postvideo: '', + }); + setPostVideoUpdated(true); + const fileInput = document.getElementById( + 'postVideoUrl', + ) as HTMLInputElement; + if (fileInput) { + fileInput.value = ''; + } + }; + function handletoggleClick(): void { + if (togglePost === 'Read more') { + setPostToggle('hide'); + } else { + setPostToggle('Read more'); + } + } + function handleEditModal(): void { + setModalVisible(false); + setMenuVisible(false); + setShowEditModal(true); + setPostFormState({ + ...postformState, + postphoto: props.postPhoto, + postvideo: props.postVideo, + }); + } + function handleDeleteModal(): void { + setModalVisible(false); + setMenuVisible(false); + setShowDeleteModal(true); + } + useEffect(() => { + setPostFormState({ + posttitle: props.postTitle, + postinfo: props.postInfo, + postphoto: props.postPhoto, + postvideo: props.postVideo, + pinned: props.pinned, + }); + }, []); + const { t } = useTranslation('translation', { + keyPrefix: 'orgPostCard', + }); + const { t: tCommon } = useTranslation('common'); + const [deletePostMutation] = useMutation(DELETE_POST_MUTATION); + const [updatePostMutation] = useMutation(UPDATE_POST_MUTATION); + const deletePost = async (): Promise => { + try { + const { data } = await deletePostMutation({ + variables: { + id: props.id, + }, + }); + if (data) { + toast.success(t('postDeleted')); + toggleShowDeleteModal(); + setTimeout(() => { + window.location.reload(); + }); + } + } catch (error: unknown) { + errorHandler(t, error); + } + }; + const handleInputEvent = ( + e: ChangeEvent, + ): void => { + const { name, value } = e.target; + setPostFormState((prevPostFormState) => ({ + ...prevPostFormState, + [name]: value, + })); + }; + const updatePostHandler = async ( + e: ChangeEvent, + ): Promise => { + e.preventDefault(); + try { + const { data } = await updatePostMutation({ + variables: { + id: props.id, + title: postformState.posttitle, + text: postformState.postinfo, + ...(postPhotoUpdated && { + imageUrl: postformState.postphoto, + }), + ...(postVideoUpdated && { + videoUrl: postformState.postvideo, + }), + }, + }); + if (data) { + toast.success(t('postUpdated')); + setTimeout(() => { + window.location.reload(); + }, 2000); + } + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + } + } + }; + return ( + <> +
    +
    + {props.postVideo && ( + + + + {props.pinned && ( + + )} + + {props.postTitle} + + + {props.postInfo} + + + {props.postAuthor} + + + + )} + {props.postPhoto ? ( + + + + {props.pinned && ( + + )} + + {props.postTitle} + + {props.postInfo} + {props.postAuthor} + + + ) : !props.postVideo ? ( + + + + + {props.pinned && ( + + )} + + {props.postTitle} + + + {props.postInfo && props.postInfo.length > 20 + ? props.postInfo.substring(0, 20) + '...' + : props.postInfo} + {' '} + + {props.postAuthor} + + + + + ) : ( + '' + )} +
    + {modalVisible && ( +
    +
    + {props.postPhoto && ( +
    + Post Image +
    + )} + {props.postVideo && ( +
    + +
    + )} + {!props.postPhoto && !props.postVideo && ( +
    + {' '} + Post Image +
    + )} +
    +

    + {t('author')}: {props.postAuthor} +

    +
    + {togglePost === 'Read more' ? ( +

    + {props.postInfo.length > 43 + ? props.postInfo.substring(0, 40) + '...' + : props.postInfo} +

    + ) : ( +

    {props.postInfo}

    + )} + +
    +
    + + +
    +
    + )} + {menuVisible && ( +
    +
    +
      +
    • + {tCommon('edit')} +
    • +
    • + {t('deletePost')} +
    • +
    • => + togglePostPin(props.id, props.pinned) + } + > + {!props.pinned ? 'Pin post' : 'Unpin post'} +
    • +
    • setMenuVisible(false)} + data-testid="closebtn" + > + {tCommon('close')} +
    • +
    +
    +
    + )} +
    + + +
    {t('deletePost')}
    + +
    + {t('deletePostMsg')} + + + + +
    + + + {t('editPost')} + +
    + + {t('postTitle')} + + {t('information')} + + {!props.postPhoto && ( + <> + {t('image')} + , + ): Promise => { + setPostFormState((prevPostFormState) => ({ + ...prevPostFormState, + postphoto: '', + })); + setPostPhotoUpdated(true); + const file = e.target.files?.[0]; + if (file) { + setPostFormState({ + ...postformState, + postphoto: await convertToBase64(file), + }); + } + }} + /> + {props.postPhoto && ( + <> + {postformState.postphoto && ( +
    + Post Image Preview + +
    + )} + + )} + + )} + {!props.postVideo && ( + <> + {t('video')} + , + ): Promise => { + setPostFormState((prevPostFormState) => ({ + ...prevPostFormState, + postvideo: '', + })); + setPostVideoUpdated(true); + const target = e.target as HTMLInputElement; + const file = target.files && target.files[0]; + if (file) { + const videoBase64 = await convertToBase64(file); + setPostFormState({ + ...postformState, + postvideo: videoBase64, + }); + } + }} + /> + {postformState.postvideo && ( +
    + + +
    + )} + + )} +
    + + + + +
    +
    + + ); +} diff --git a/src/components/OrgProfileFieldSettings/OrgProfileFieldSettings.module.css b/src/components/OrgProfileFieldSettings/OrgProfileFieldSettings.module.css new file mode 100644 index 0000000000..851f70ce39 --- /dev/null +++ b/src/components/OrgProfileFieldSettings/OrgProfileFieldSettings.module.css @@ -0,0 +1,24 @@ +.customDataTable { + width: 100%; + border-collapse: collapse; +} + +.customDataTable th, +.customDataTable td { + padding: 8px; + text-align: left; +} + +.customDataTable th { + background-color: #f2f2f2; +} +form { + display: flex; + flex-direction: column; + gap: 10px; +} + +.saveButton { + width: 10em; + align-self: self-end; +} diff --git a/src/components/OrgProfileFieldSettings/OrgProfileFieldSettings.test.tsx b/src/components/OrgProfileFieldSettings/OrgProfileFieldSettings.test.tsx new file mode 100644 index 0000000000..2630c6c4ee --- /dev/null +++ b/src/components/OrgProfileFieldSettings/OrgProfileFieldSettings.test.tsx @@ -0,0 +1,280 @@ +import React from 'react'; +import { act, render, screen } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import userEvent from '@testing-library/user-event'; +import { I18nextProvider } from 'react-i18next'; +import OrgProfileFieldSettings from './OrgProfileFieldSettings'; +import i18nForTest from 'utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { + ADD_CUSTOM_FIELD, + REMOVE_CUSTOM_FIELD, +} from 'GraphQl/Mutations/mutations'; +import { ORGANIZATION_CUSTOM_FIELDS } from 'GraphQl/Queries/Queries'; +import { ToastContainer, toast } from 'react-toastify'; + +const MOCKS = [ + { + request: { + query: ADD_CUSTOM_FIELD, + variables: { + type: '', + name: '', + }, + }, + result: { + data: { + addOrganizationCustomField: { + name: 'Custom Field Name', + type: 'string', + }, + }, + }, + }, + + { + request: { + query: REMOVE_CUSTOM_FIELD, + variables: { customFieldId: 'adsdasdsa334343yiu423434' }, + }, + result: { + data: { + removeOrganizationCustomField: { + type: '', + name: '', + }, + }, + }, + }, + + { + request: { + query: ORGANIZATION_CUSTOM_FIELDS, + variables: {}, + }, + result: { + data: { + customFieldsByOrganization: [ + { + _id: 'adsdasdsa334343yiu423434', + type: 'fieldType', + name: 'fieldName', + }, + ], + }, + }, + }, +]; + +const ERROR_MOCKS = [ + { + request: { + query: ADD_CUSTOM_FIELD, + variables: { + type: '', + name: '', + }, + }, + error: new Error('Failed to add custom field'), + }, + { + request: { + query: REMOVE_CUSTOM_FIELD, + variables: { + customFieldId: 'adsdasdsa334343yiu423434', + }, + }, + error: new Error('Failed to remove custom field'), + }, + { + request: { + query: ORGANIZATION_CUSTOM_FIELDS, + variables: {}, + }, + result: { + data: { + customFieldsByOrganization: [ + { + _id: 'adsdasdsa334343yiu423434', + type: 'fieldType', + name: 'fieldName', + }, + ], + }, + }, + }, +]; + +const ORGANIZATION_CUSTOM_FIELDS_ERROR_MOCKS = [ + { + request: { + query: ORGANIZATION_CUSTOM_FIELDS, + variables: {}, + }, + error: new Error('Failed to fetch custom field'), + }, +]; + +const NO_C_FIELD_MOCK = [ + { + request: { + query: ADD_CUSTOM_FIELD, + variables: { + type: 'fieldType', + name: 'fieldName', + }, + }, + result: { + data: { + addOrganizationCustomField: { + name: 'Custom Field Name', + type: 'string', + }, + }, + }, + }, + + { + request: { + query: ORGANIZATION_CUSTOM_FIELDS, + variables: {}, + }, + result: { + data: { + customFieldsByOrganization: [], + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(NO_C_FIELD_MOCK, true); +const link3 = new StaticMockLink(ERROR_MOCKS, true); +const link4 = new StaticMockLink(ORGANIZATION_CUSTOM_FIELDS_ERROR_MOCKS, true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +describe('Testing Save Button', () => { + test('Testing Failure Case For Fetching Custom field', async () => { + render( + + + + + , + ); + + await wait(); + expect( + screen.queryByText('Failed to fetch custom field'), + ).toBeInTheDocument(); + }); + test('Saving Organization Custom Field', async () => { + render( + + + + + + , + ); + + await wait(); + userEvent.click(screen.getByTestId('saveChangesBtn')); + await wait(); + expect(screen.queryByText('Field added successfully')).toBeInTheDocument(); + }); + + test('Testing Failure Case For Saving Custom Field', async () => { + render( + + + + + + , + ); + await wait(); + userEvent.click(screen.getByTestId('saveChangesBtn')); + await wait(); + expect( + screen.queryByText('Failed to add custom field'), + ).toBeInTheDocument(); + await wait(); + userEvent.type(screen.getByTestId('customFieldInput'), 'Age{enter}'); + await wait(); + expect( + screen.queryByText('Failed to add custom field'), + ).toBeInTheDocument(); + }); + + test('Testing Typing Organization Custom Field Name', async () => { + const { getByTestId } = render( + + + + + , + ); + + await wait(); + + const fieldNameInput = getByTestId('customFieldInput'); + userEvent.type(fieldNameInput, 'Age'); + }); + test('When No Custom Data is Present', async () => { + const { getByText } = render( + + + + + , + ); + + await wait(); + expect(getByText('No custom fields available')).toBeInTheDocument(); + }); + test('Testing Remove Custom Field Button', async () => { + render( + + + + + + , + ); + + await wait(); + userEvent.click(screen.getByTestId('removeCustomFieldBtn')); + await wait(); + expect( + screen.queryByText('Field removed successfully'), + ).toBeInTheDocument(); + }); + + test('Testing Failure Case For Removing Custom Field', async () => { + const toastSpy = jest.spyOn(toast, 'error'); + render( + + + + + + , + ); + await wait(); + userEvent.click(screen.getByTestId('removeCustomFieldBtn')); + await wait(); + expect(toastSpy).toHaveBeenCalledWith('Failed to remove custom field'); + }); +}); diff --git a/src/components/OrgProfileFieldSettings/OrgProfileFieldSettings.tsx b/src/components/OrgProfileFieldSettings/OrgProfileFieldSettings.tsx new file mode 100644 index 0000000000..ba2d3a9c02 --- /dev/null +++ b/src/components/OrgProfileFieldSettings/OrgProfileFieldSettings.tsx @@ -0,0 +1,174 @@ +import { useMutation, useQuery } from '@apollo/client'; +import React, { useState } from 'react'; +import { FaTrash } from 'react-icons/fa'; +import { Form } from 'react-bootstrap'; +import Button from 'react-bootstrap/Button'; +import { + ADD_CUSTOM_FIELD, + REMOVE_CUSTOM_FIELD, +} from 'GraphQl/Mutations/mutations'; +import { ORGANIZATION_CUSTOM_FIELDS } from 'GraphQl/Queries/Queries'; +import styles from './OrgProfileFieldSettings.module.css'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; +import EditOrgCustomFieldDropDown from 'components/EditCustomFieldDropDown/EditCustomFieldDropDown'; +import { useParams } from 'react-router-dom'; + +export interface InterfaceCustomFieldData { + type: string; + name: string; +} + +const OrgProfileFieldSettings = (): JSX.Element => { + const { t } = useTranslation('translation', { + keyPrefix: 'orgProfileField', + }); + const { t: tCommon } = useTranslation('common'); + + const [customFieldData, setCustomFieldData] = + useState({ + type: '', + name: '', + }); + const { orgId: currentOrgId } = useParams(); + + const [addCustomField] = useMutation(ADD_CUSTOM_FIELD); + const [removeCustomField] = useMutation(REMOVE_CUSTOM_FIELD); + + const { loading, error, data, refetch } = useQuery( + ORGANIZATION_CUSTOM_FIELDS, + { + variables: { + customFieldsByOrganizationId: currentOrgId, + }, + }, + ); + + const handleSave = async (): Promise => { + try { + await addCustomField({ + variables: { + organizationId: currentOrgId, + ...customFieldData, + }, + }); + toast.success(t('fieldSuccessMessage')); + setCustomFieldData({ type: '', name: '' }); + refetch(); + } catch (error) { + toast.error((error as Error).message); + } + }; + + const handleRemove = async (customFieldId: string): Promise => { + try { + await removeCustomField({ + variables: { + organizationId: currentOrgId, + customFieldId: customFieldId, + }, + }); + + toast.success(t('fieldRemovalSuccess')); + refetch(); + } catch (error) { + toast.error((error as Error).message); + } + }; + + if (loading) return

    {tCommon('loading')}

    ; + if (error) return

    {error.message}

    ; + + return ( +
    + {data.customFieldsByOrganization.length === 0 ? ( +

    {t('noCustomField')}

    + ) : ( + + + {data.customFieldsByOrganization.map( + ( + field: { + _id: string; + name: string; + type: string; + }, + index: number, + ) => ( + + + + + + ), + )} + +
    {field.name}{field.type} + +
    + )} +
    +
    +
    +
    +
    +
    + {t('customFieldName')} + { + setCustomFieldData({ + ...customFieldData, + name: event.target.value, + }); + }} + onKeyDown={(event) => { + if (event.key === 'Enter') { + event.preventDefault(); + handleSave(); + } + }} + /> +
    + +
    + + {t('customFieldType')} + + +
    + + +
    +
    +
    +
    +
    + ); +}; + +export default OrgProfileFieldSettings; diff --git a/src/components/OrgUpdate/OrgUpdate.module.css b/src/components/OrgUpdate/OrgUpdate.module.css new file mode 100644 index 0000000000..fca7ac5e5b --- /dev/null +++ b/src/components/OrgUpdate/OrgUpdate.module.css @@ -0,0 +1,13 @@ +.message { + height: 420px; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.icon { + transform: scale(1.5); + color: var(--bs-danger); + margin-bottom: 1rem; +} diff --git a/src/components/OrgUpdate/OrgUpdate.test.tsx b/src/components/OrgUpdate/OrgUpdate.test.tsx new file mode 100644 index 0000000000..9c56a61d78 --- /dev/null +++ b/src/components/OrgUpdate/OrgUpdate.test.tsx @@ -0,0 +1,242 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { act, fireEvent, render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { I18nextProvider } from 'react-i18next'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18nForTest from 'utils/i18nForTest'; +import OrgUpdate from './OrgUpdate'; +import { + MOCKS, + MOCKS_ERROR_ORGLIST, + MOCKS_ERROR_UPDATE_ORGLIST, +} from './OrgUpdateMocks'; + +const link = new StaticMockLink(MOCKS, true); + +async function wait(ms = 500): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +describe('Testing Organization Update', () => { + const props = { + orgId: '123', + }; + + const formData = { + name: 'Palisadoes Organization', + description: 'This is a updated description', + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + displayImage: new File(['hello'], 'hello.png', { type: 'image/png' }), + userRegistrationRequired: false, + isVisible: true, + }; + + global.alert = jest.fn(); + + test('should render props and text elements test for the page component along with mock data', async () => { + act(() => { + render( + + + + + , + ); + }); + await wait(); + // Check labels are present or not + expect(screen.getByText('Name')).toBeInTheDocument(); + expect(screen.getByText('Description')).toBeInTheDocument(); + expect(screen.getByText('Address')).toBeInTheDocument(); + expect(screen.getByText('Display Image:')).toBeInTheDocument(); + expect(screen.getByText(/Registration/)).toBeInTheDocument(); + expect(screen.getByText('Visible in Search:')).toBeInTheDocument(); + + // Get the input fields, and btns + const name = screen.getByPlaceholderText(/Enter Organization Name/i); + const des = screen.getByPlaceholderText(/Description/i); + const city = screen.getByPlaceholderText(/City/i); + const countryCode = screen.getByTestId('countrycode'); + const line1 = screen.getByPlaceholderText(/Line 1/i); + const line2 = screen.getByPlaceholderText(/Line 2/i); + const dependentLocality = + screen.getByPlaceholderText(/Dependent Locality/i); + const sortingCode = screen.getByPlaceholderText(/Sorting code/i); + const postalCode = screen.getByPlaceholderText(/Postal Code/i); + const userRegistrationRequired = + screen.getByPlaceholderText(/Registration/i); + const isVisible = screen.getByPlaceholderText(/Visible/i); + + // Checking if form fields got updated according to the mock data + expect(name).toHaveValue('Palisadoes'); + expect(des).toHaveValue('Equitable Access to STEM Education Jobs'); + expect(city).toHaveValue('Kingston'); + expect(countryCode).toHaveValue('JM'); + expect(dependentLocality).toHaveValue('Sample Dependent Locality'); + expect(line1).toHaveValue('123 Jamaica Street'); + expect(line2).toHaveValue('Apartment 456'); + expect(postalCode).toHaveValue('JM12345'); + expect(sortingCode).toHaveValue('ABC-123'); + expect(userRegistrationRequired).toBeChecked(); + expect(isVisible).not.toBeChecked(); + }); + + test('Should Update organization properly', async () => { + await act(async () => { + render( + + + + + , + ); + }); + + await wait(); + + // Get the input fields, and btns + const name = screen.getByPlaceholderText(/Enter Organization Name/i); + const des = screen.getByPlaceholderText(/Description/i); + + const city = screen.getByPlaceholderText(/City/i); + const countryCode = screen.getByTestId('countrycode'); + const line1 = screen.getByPlaceholderText(/Line 1/i); + const line2 = screen.getByPlaceholderText(/Line 2/i); + const dependentLocality = + screen.getByPlaceholderText(/Dependent Locality/i); + const sortingCode = screen.getByPlaceholderText(/Sorting code/i); + const postalCode = screen.getByPlaceholderText(/Postal Code/i); + const displayImage = screen.getByPlaceholderText(/Display Image/i); + const userRegistrationRequired = + screen.getByPlaceholderText(/Registration/i); + const isVisible = screen.getByPlaceholderText(/Visible/i); + const saveChangesBtn = screen.getByText(/Save Changes/i); + + // Emptying the text fields to add updated data + fireEvent.change(name, { target: { value: '' } }); + fireEvent.change(des, { target: { value: '' } }); + fireEvent.change(city, { target: { value: '' } }); + fireEvent.change(line1, { target: { value: '' } }); + fireEvent.change(line2, { target: { value: '' } }); + fireEvent.change(postalCode, { target: { value: '' } }); + fireEvent.change(sortingCode, { target: { value: '' } }); + fireEvent.change(dependentLocality, { target: { value: '' } }); + + // Mocking filling form behaviour + userEvent.type(name, formData.name); + userEvent.type(des, formData.description); + userEvent.type(city, formData.address.city); + userEvent.selectOptions(countryCode, formData.address.countryCode); + userEvent.type(line1, formData.address.line1); + userEvent.type(line2, formData.address.line2); + userEvent.type(postalCode, formData.address.postalCode); + userEvent.type(dependentLocality, formData.address.dependentLocality); + userEvent.type(sortingCode, formData.address.sortingCode); + userEvent.upload(displayImage, formData.displayImage); + userEvent.click(userRegistrationRequired); + userEvent.click(isVisible); + + await wait(); + userEvent.click(saveChangesBtn); + + // Checking if the form got update accordingly + expect(name).toHaveValue(formData.name); + expect(des).toHaveValue(formData.description); + expect(city).toHaveValue(formData.address.city); + expect(countryCode).toHaveValue(formData.address.countryCode); + expect(dependentLocality).toHaveValue(formData.address.dependentLocality); + expect(line1).toHaveValue(formData.address.line1); + expect(line2).toHaveValue(formData.address.line2); + expect(postalCode).toHaveValue(formData.address.postalCode); + expect(sortingCode).toHaveValue(formData.address.sortingCode); + expect(displayImage).toBeTruthy(); + expect(userRegistrationRequired).not.toBeChecked(); + expect(isVisible).toBeChecked(); + }); + + test('Should render error occured text when Organization Could not be found', async () => { + act(() => { + render( + + + + + , + ); + }); + await wait(); + expect(screen.getByText(/Mock Graphql Error/i)).toBeInTheDocument(); + }); + + test('Should show error occured toast when Organization could not be updated', async () => { + await act(async () => { + render( + + + + + , + ); + }); + + await wait(); + + // Get the input fields, and btns + const name = screen.getByPlaceholderText(/Enter Organization Name/i); + const des = screen.getByPlaceholderText(/Description/i); + const city = screen.getByPlaceholderText(/City/i); + const countryCode = screen.getByTestId('countrycode'); + const line1 = screen.getByPlaceholderText(/Line 1/i); + const line2 = screen.getByPlaceholderText(/Line 2/i); + const dependentLocality = + screen.getByPlaceholderText(/Dependent Locality/i); + const sortingCode = screen.getByPlaceholderText(/Sorting code/i); + const postalCode = screen.getByPlaceholderText(/Postal Code/i); + const displayImage = screen.getByPlaceholderText(/Display Image/i); + const userRegistrationRequired = + screen.getByPlaceholderText(/Registration/i); + const isVisible = screen.getByPlaceholderText(/Visible/i); + const saveChangesBtn = screen.getByText(/Save Changes/i); + + // Emptying the text fields to add updated data + fireEvent.change(name, { target: { value: '' } }); + fireEvent.change(des, { target: { value: '' } }); + fireEvent.change(city, { target: { value: '' } }); + fireEvent.change(line1, { target: { value: '' } }); + fireEvent.change(line2, { target: { value: '' } }); + fireEvent.change(postalCode, { target: { value: '' } }); + fireEvent.change(sortingCode, { target: { value: '' } }); + fireEvent.change(dependentLocality, { target: { value: '' } }); + + // Mocking filling form behaviour + userEvent.type(name, formData.name); + userEvent.type(des, formData.description); + userEvent.type(city, formData.address.city); + userEvent.selectOptions(countryCode, formData.address.countryCode); + userEvent.type(line1, formData.address.line1); + userEvent.type(line2, formData.address.line2); + userEvent.type(postalCode, formData.address.postalCode); + userEvent.type(dependentLocality, formData.address.dependentLocality); + userEvent.type(sortingCode, formData.address.sortingCode); + userEvent.upload(displayImage, formData.displayImage); + userEvent.click(userRegistrationRequired); + userEvent.click(isVisible); + + await wait(); + userEvent.click(saveChangesBtn); + }); +}); diff --git a/src/components/OrgUpdate/OrgUpdate.tsx b/src/components/OrgUpdate/OrgUpdate.tsx new file mode 100644 index 0000000000..e2820f3b49 --- /dev/null +++ b/src/components/OrgUpdate/OrgUpdate.tsx @@ -0,0 +1,344 @@ +import React, { useState, useEffect } from 'react'; +import { useMutation, useQuery } from '@apollo/client'; +import Button from 'react-bootstrap/Button'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; + +import type { ApolloError } from '@apollo/client'; +import { WarningAmberRounded } from '@mui/icons-material'; +import { UPDATE_ORGANIZATION_MUTATION } from 'GraphQl/Mutations/mutations'; +import { ORGANIZATIONS_LIST } from 'GraphQl/Queries/Queries'; +import Loader from 'components/Loader/Loader'; +import { Col, Form, Row } from 'react-bootstrap'; +import convertToBase64 from 'utils/convertToBase64'; +import { errorHandler } from 'utils/errorHandler'; +import styles from './OrgUpdate.module.css'; +import type { + InterfaceQueryOrganizationsListObject, + InterfaceAddress, +} from 'utils/interfaces'; +import { countryOptions } from 'utils/formEnumFields'; + +interface InterfaceOrgUpdateProps { + orgId: string; +} + +function orgUpdate(props: InterfaceOrgUpdateProps): JSX.Element { + const { orgId } = props; + + const [formState, setFormState] = useState<{ + orgName: string; + orgDescrip: string; + address: InterfaceAddress; + orgImage: string | null; + }>({ + orgName: '', + orgDescrip: '', + address: { + city: '', + countryCode: '', + dependentLocality: '', + line1: '', + line2: '', + postalCode: '', + sortingCode: '', + state: '', + }, + orgImage: null, + }); + + const handleInputChange = (fieldName: string, value: string): void => { + setFormState((prevState) => ({ + ...prevState, + address: { + ...prevState.address, + [fieldName]: value, + }, + })); + }; + + const [userRegistrationRequiredChecked, setuserRegistrationRequiredChecked] = + React.useState(false); + const [visiblechecked, setVisibleChecked] = React.useState(false); + + const [login] = useMutation(UPDATE_ORGANIZATION_MUTATION); + + const { t } = useTranslation('translation', { + keyPrefix: 'orgUpdate', + }); + const { t: tCommon } = useTranslation('common'); + + const { + data, + loading, + refetch, + error, + }: { + data?: { + organizations: InterfaceQueryOrganizationsListObject[]; + }; + loading: boolean; + refetch: (variables: { id: string }) => void; + error?: ApolloError; + } = useQuery(ORGANIZATIONS_LIST, { + variables: { id: orgId }, + notifyOnNetworkStatusChange: true, + }); + + useEffect(() => { + let isMounted = true; + if (data && isMounted) { + setFormState({ + ...formState, + orgName: data.organizations[0].name, + orgDescrip: data.organizations[0].description, + address: data.organizations[0].address, + }); + setuserRegistrationRequiredChecked( + data.organizations[0].userRegistrationRequired, + ); + setVisibleChecked(data.organizations[0].visibleInSearch); + } + return () => { + isMounted = false; + }; + }, [data, orgId]); + + const onSaveChangesClicked = async (): Promise => { + try { + const { data } = await login({ + variables: { + id: orgId, + name: formState.orgName, + description: formState.orgDescrip, + address: { + city: formState.address.city, + countryCode: formState.address.countryCode, + dependentLocality: formState.address.dependentLocality, + line1: formState.address.line1, + line2: formState.address.line2, + postalCode: formState.address.postalCode, + sortingCode: formState.address.sortingCode, + state: formState.address.state, + }, + userRegistrationRequired: userRegistrationRequiredChecked, + visibleInSearch: visiblechecked, + file: formState.orgImage, + }, + }); + // istanbul ignore next + if (data) { + refetch({ id: orgId }); + toast.success(t('successfulUpdated')); + } + } catch (error: unknown) { + errorHandler(t, error); + } + }; + + if (loading) { + return ; + } + + if (error) { + return ( +
    + +
    + Error occured while loading Organization Data +
    + {`${error.message}`} +
    +
    + ); + } + + return ( + <> +
    +
    + {tCommon('name')} + { + setFormState({ + ...formState, + orgName: e.target.value, + }); + }} + /> + {tCommon('description')} + { + setFormState({ + ...formState, + orgDescrip: e.target.value, + }); + }} + /> + {tCommon('address')} + + + { + const countryCode = e.target.value; + handleInputChange('countryCode', countryCode); + }} + > + + {countryOptions.map((country) => ( + + ))} + + + + handleInputChange('city', e.target.value)} + /> + + + + + handleInputChange('state', e.target.value)} + /> + + + + handleInputChange('dependentLocality', e.target.value) + } + /> + + + + + handleInputChange('line1', e.target.value)} + /> + + + handleInputChange('line2', e.target.value)} + /> + + + + + + handleInputChange('postalCode', e.target.value) + } + /> + + + + handleInputChange('sortingCode', e.target.value) + } + /> + + + + + + {t('userRegistrationRequired')}: + + + setuserRegistrationRequiredChecked( + !userRegistrationRequiredChecked, + ) + } + /> + + + + {t('isVisibleInSearch')}: + + setVisibleChecked(!visiblechecked)} + /> + + + {tCommon('displayImage')}: + => { + const target = e.target as HTMLInputElement; + const file = target.files && target.files[0]; + /* istanbul ignore else */ + if (file) + setFormState({ + ...formState, + orgImage: await convertToBase64(file), + }); + }} + data-testid="organisationImage" + /> +
    + +
    + +
    + + ); +} +export default orgUpdate; diff --git a/src/components/OrgUpdate/OrgUpdateMocks.ts b/src/components/OrgUpdate/OrgUpdateMocks.ts new file mode 100644 index 0000000000..4c7f704719 --- /dev/null +++ b/src/components/OrgUpdate/OrgUpdateMocks.ts @@ -0,0 +1,204 @@ +import { UPDATE_ORGANIZATION_MUTATION } from 'GraphQl/Mutations/mutations'; +import { ORGANIZATIONS_LIST } from 'GraphQl/Queries/Queries'; + +export const MOCKS = [ + { + request: { + query: ORGANIZATIONS_LIST, + variables: { id: '123' }, + }, + result: { + data: { + organizations: [ + { + _id: '123', + image: null, + name: 'Palisadoes', + description: 'Equitable Access to STEM Education Jobs', + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + userRegistrationRequired: true, + visibleInSearch: false, + creator: { + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@example.com', + }, + members: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@gmail.com', + }, + admins: [ + { + _id: '123', + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@gmail.com', + createdAt: '12-03-2024', + }, + ], + membershipRequests: { + _id: '456', + user: { + firstName: 'Sam', + lastName: 'Smith', + email: 'samsmith@gmail.com', + }, + }, + blockedUsers: [], + }, + ], + }, + }, + }, + { + request: { + query: UPDATE_ORGANIZATION_MUTATION, + variables: { + id: '123', + name: 'Updated Organization', + description: 'This is an updated test organization', + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + image: new File(['hello'], 'hello.png', { type: 'image/png' }), + userRegistrationRequired: true, + visibleInSearch: false, + }, + }, + result: { + data: { + updateOrganization: { + _id: '123', + name: 'Updated Organization', + description: 'This is an updated test organization', + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + userRegistrationRequired: true, + visibleInSearch: false, + }, + }, + }, + }, +]; + +export const MOCKS_ERROR_ORGLIST = [ + { + request: { + query: ORGANIZATIONS_LIST, + variables: { id: '123' }, + }, + error: new Error('Mock Graphql Error'), + }, +]; + +export const MOCKS_ERROR_UPDATE_ORGLIST = [ + { + request: { + query: ORGANIZATIONS_LIST, + variables: { id: '123' }, + }, + result: { + data: { + organizations: [ + { + _id: '123', + image: null, + name: 'Palisadoes', + description: 'Equitable Access to STEM Education Jobs', + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + userRegistrationRequired: true, + visibleInSearch: false, + creator: { + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@example.com', + }, + members: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@gmail.com', + }, + admins: [ + { + _id: '123', + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@gmail.com', + createdAt: '12-03-2024', + }, + ], + membershipRequests: { + _id: '456', + user: { + firstName: 'Sam', + lastName: 'Smith', + email: 'samsmith@gmail.com', + }, + }, + blockedUsers: [], + }, + ], + }, + }, + }, + { + request: { + query: UPDATE_ORGANIZATION_MUTATION, + variables: { + id: '123', + name: 'Updated Organization', + description: 'This is an updated test organization', + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + image: new File(['hello'], 'hello.png', { type: 'image/png' }), + userRegistrationRequired: true, + visibleInSearch: false, + }, + }, + erorr: new Error('Mock Graphql Updating Organization Error'), + }, +]; diff --git a/src/components/OrganizationCard/OrganizationCard.module.css b/src/components/OrganizationCard/OrganizationCard.module.css new file mode 100644 index 0000000000..6c65b8258b --- /dev/null +++ b/src/components/OrganizationCard/OrganizationCard.module.css @@ -0,0 +1,46 @@ +.alignimg { + border-radius: 50%; + background-blend-mode: darken; + height: 65px; + width: 65px; +} + +.box { + color: #ffbd59; +} + +.box :hover { + color: #ffbd59; +} + +.first_box { + display: flex; + flex-direction: row; + padding-bottom: 10px; + padding-top: 10px; +} + +.second_box { + padding-left: 20px; + padding-top: 10px; +} + +.second_box > h4 { + font-size: 10; + font-weight: bold; + text-decoration: none; + color: black; +} + +.second_box > h5 { + text-decoration: none; + font-size: 10; + font-weight: 100; + color: #969696; +} + +.deco { + border: 1px solid #dfdfdf; + width: 65vw; + height: 0px !important; +} diff --git a/src/components/OrganizationCard/OrganizationCard.test.tsx b/src/components/OrganizationCard/OrganizationCard.test.tsx new file mode 100644 index 0000000000..e0095d20b2 --- /dev/null +++ b/src/components/OrganizationCard/OrganizationCard.test.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import OrganizationCard from './OrganizationCard'; + +describe('Testing the Organization Card', () => { + test('should render props and text elements test for the page component', () => { + const props = { + id: '123', + key: '456', + image: 'https://via.placeholder.com/80', + firstName: 'John', + lastName: 'Doe', + name: 'Sample', + }; + + render(); + + expect(screen.getByText(props.name)).toBeInTheDocument(); + expect(screen.getByText(/Owner:/i)).toBeInTheDocument(); + expect(screen.getByText(props.firstName)).toBeInTheDocument(); + expect(screen.getByText(props.lastName)).toBeInTheDocument(); + }); + + test('Should render text elements when props value is not passed', () => { + const props = { + id: '123', + key: '456', + image: '', + firstName: 'John', + lastName: 'Doe', + name: 'Sample', + }; + + render(); + + expect(screen.getByText(props.name)).toBeInTheDocument(); + expect(screen.getByText(/Owner:/i)).toBeInTheDocument(); + expect(screen.getByText(props.firstName)).toBeInTheDocument(); + expect(screen.getByText(props.lastName)).toBeInTheDocument(); + }); +}); diff --git a/src/components/OrganizationCard/OrganizationCard.tsx b/src/components/OrganizationCard/OrganizationCard.tsx new file mode 100644 index 0000000000..ba90f3f83f --- /dev/null +++ b/src/components/OrganizationCard/OrganizationCard.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import styles from './OrganizationCard.module.css'; + +interface InterfaceOrganizationCardProps { + key: any; + image: string; + id: string; + name: string; + lastName: string; + firstName: string; +} + +function organizationCard(props: InterfaceOrganizationCardProps): JSX.Element { + const uri = '/superorghome/i=' + props.id; + + return ( + <> + +
    +
    + {props.image ? ( + + ) : ( + + )} +
    +

    {props.name}

    +
    + Owner: + {props.firstName} + +   + {props.lastName} + +
    +
    +
    +
    +
    +
    + + ); +} + +export {}; +export default organizationCard; diff --git a/src/components/OrganizationCardStart/OrganizationCardStart.module.css b/src/components/OrganizationCardStart/OrganizationCardStart.module.css new file mode 100644 index 0000000000..6c65b8258b --- /dev/null +++ b/src/components/OrganizationCardStart/OrganizationCardStart.module.css @@ -0,0 +1,46 @@ +.alignimg { + border-radius: 50%; + background-blend-mode: darken; + height: 65px; + width: 65px; +} + +.box { + color: #ffbd59; +} + +.box :hover { + color: #ffbd59; +} + +.first_box { + display: flex; + flex-direction: row; + padding-bottom: 10px; + padding-top: 10px; +} + +.second_box { + padding-left: 20px; + padding-top: 10px; +} + +.second_box > h4 { + font-size: 10; + font-weight: bold; + text-decoration: none; + color: black; +} + +.second_box > h5 { + text-decoration: none; + font-size: 10; + font-weight: 100; + color: #969696; +} + +.deco { + border: 1px solid #dfdfdf; + width: 65vw; + height: 0px !important; +} diff --git a/src/components/OrganizationCardStart/OrganizationCardStart.test.tsx b/src/components/OrganizationCardStart/OrganizationCardStart.test.tsx new file mode 100644 index 0000000000..2a9f03a9be --- /dev/null +++ b/src/components/OrganizationCardStart/OrganizationCardStart.test.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import OrganizationCardStart from './OrganizationCardStart'; + +describe('Testing the Organization Cards', () => { + test('should render props and text elements test for the page component', () => { + const props = { + id: '123', + key: '456', + image: 'https://via.placeholder.com/80', + name: 'Sample', + }; + + render(); + + expect(screen.getByText(props.name)).toBeInTheDocument(); + }); + + test('Should render text elements when props value is not passed', () => { + const props = { + id: '123', + key: '456', + image: '', + name: 'Sample', + }; + + render(); + + expect(screen.getByText(props.name)).toBeInTheDocument(); + }); +}); diff --git a/src/components/OrganizationCardStart/OrganizationCardStart.tsx b/src/components/OrganizationCardStart/OrganizationCardStart.tsx new file mode 100644 index 0000000000..4fdbc0edb2 --- /dev/null +++ b/src/components/OrganizationCardStart/OrganizationCardStart.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import styles from './OrganizationCardStart.module.css'; + +interface InterfaceOrganizationCardStartProps { + key: any; + image: string; + id: string; + name: string; +} + +function organizationCardStart( + props: InterfaceOrganizationCardStartProps, +): JSX.Element { + const uri = '/orghome/i=' + props.id; + + return ( + <> + +
    +
    + {props.image ? ( + + ) : ( + + )} +
    +

    {props.name}

    +
    +
    +
    +
    +
    +
    + + ); +} + +export default organizationCardStart; diff --git a/src/components/OrganizationDashCards/CardItem.module.css b/src/components/OrganizationDashCards/CardItem.module.css new file mode 100644 index 0000000000..bfb85cb1bb --- /dev/null +++ b/src/components/OrganizationDashCards/CardItem.module.css @@ -0,0 +1,81 @@ +.cardItem { + position: relative; + display: flex; + align-items: center; + border: 1px solid var(--bs-gray-200); + border-radius: 8px; + margin-top: 20px; +} + +.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 .iconWrapper .dangerOverlay { + background: var(--bs-danger); + 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; + display: -webkit-box; + -webkit-line-clamp: 1; + line-clamp: 1; + -webkit-box-orient: vertical; + margin-left: 3px; +} + +.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: rgb(33, 208, 21); +} + +.rightCard { + display: flex; + gap: 7px; + min-width: 170px; + justify-content: center; + flex-direction: column; + margin-left: 10px; + overflow-x: hidden; + width: 210px; +} diff --git a/src/components/OrganizationDashCards/CardItem.test.tsx b/src/components/OrganizationDashCards/CardItem.test.tsx new file mode 100644 index 0000000000..31f3474607 --- /dev/null +++ b/src/components/OrganizationDashCards/CardItem.test.tsx @@ -0,0 +1,62 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import CardItem from './CardItem'; +import type { InterfaceCardItem } from './CardItem'; +import dayjs from 'dayjs'; + +describe('Testing the Organization Card', () => { + test('Should render props and text elements For event card', () => { + const props: InterfaceCardItem = { + type: 'Event', + title: 'Event Title', + startdate: '2023-09-13', + enddate: '2023-09-14', + location: 'Event Location', + }; + + render(); + + expect(screen.getByText(/Event Title/i)).toBeInTheDocument(); + expect( + screen.getByText( + `${dayjs(props.startdate).format('MMM D, YYYY')} - ${dayjs( + props.enddate, + ).format('MMM D, YYYY')}`, + ), + ).toBeInTheDocument(); + expect(screen.getByText(/Event Location/i)).toBeInTheDocument(); + }); + + test('Should render props and text elements for Post card', () => { + const props: InterfaceCardItem = { + type: 'Post', + title: 'Post Title', + time: '2023-09-03', + creator: { + email: 'johndoe@example.com', + firstName: 'John', + lastName: 'Doe', + __typename: 'User', + _id: '1', + }, + }; + + render(); + + expect(screen.getByText(/Post Title/i)).toBeInTheDocument(); + expect( + screen.getByText(dayjs(props.time).format('MMM D, YYYY')), + ).toBeInTheDocument(); + expect(screen.getByText(/John Doe/i)).toBeInTheDocument(); + }); + + test('Should render props and text elements for Membership Request card', () => { + const props: InterfaceCardItem = { + type: 'MembershipRequest', + title: 'Membership Request Title', + }; + + render(); + expect(screen.getByText(/Membership Request Title/i)).toBeInTheDocument(); + }); +}); diff --git a/src/components/OrganizationDashCards/CardItem.tsx b/src/components/OrganizationDashCards/CardItem.tsx new file mode 100644 index 0000000000..b020f1885f --- /dev/null +++ b/src/components/OrganizationDashCards/CardItem.tsx @@ -0,0 +1,114 @@ +import React from 'react'; +import { ReactComponent as EventsIcon } from 'assets/svgs/cardItemEvent.svg'; +import { ReactComponent as PostsIcon } from 'assets/svgs/post.svg'; +import { ReactComponent as MarkerIcon } from 'assets/svgs/cardItemLocation.svg'; +import { ReactComponent as DateIcon } from 'assets/svgs/cardItemDate.svg'; +import { ReactComponent as UserIcon } from 'assets/svgs/user.svg'; +import dayjs from 'dayjs'; +import styles from './CardItem.module.css'; +import { PersonAddAlt1Rounded } from '@mui/icons-material'; + +export interface InterfaceCardItem { + type: 'Event' | 'Post' | 'MembershipRequest'; + title: string; + time?: string; + startdate?: string; + enddate?: string; + creator?: any; + location?: string; +} + +const cardItem = (props: InterfaceCardItem): JSX.Element => { + const { creator, type, title, startdate, time, enddate, location } = props; + return ( + <> +
    +
    +
    + {type == 'Event' ? ( + + ) : type == 'Post' ? ( + + ) : ( + type == 'MembershipRequest' && ( + + ) + )} +
    + +
    + {creator && ( + + {' '} + {' '} + + {creator.firstName} {creator.lastName} + + + )} + + {title && ( + + {title} + + )} + + {location && ( + + {' '} + {location} + + )} + {type == 'Event' && startdate && ( + + {type === 'Event' && ( + + )}{' '} + {dayjs(startdate).format('MMM D, YYYY')} -{' '} + {dayjs(enddate).format('MMM D, YYYY')} + + )} + {type == 'Post' && time && ( + + {type === 'Post' && ( + + )}{' '} + {dayjs(time).format('MMM D, YYYY')} + + )} +
    +
    + + ); +}; + +export default cardItem; diff --git a/src/components/OrganizationDashCards/CardItemLoading.tsx b/src/components/OrganizationDashCards/CardItemLoading.tsx new file mode 100644 index 0000000000..923128c2f2 --- /dev/null +++ b/src/components/OrganizationDashCards/CardItemLoading.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import styles from './CardItem.module.css'; + +const cardItemLoading = (): JSX.Element => { + return ( + <> +
    +
    +
    +
    + +   + +
    + + ); +}; + +export default cardItemLoading; diff --git a/src/components/OrganizationDashCards/DashboardCard.test.tsx b/src/components/OrganizationDashCards/DashboardCard.test.tsx new file mode 100644 index 0000000000..71e5e1fed0 --- /dev/null +++ b/src/components/OrganizationDashCards/DashboardCard.test.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import DashboardCard from './DashboardCard'; + +describe('Testing the Dashboard Card', () => { + test('should render props and text elements For event card', () => { + const props = { + icon: , + title: 'Example Title', + count: 100, + }; + + render(); + + expect(screen.getByText(/Example Title/i)).toBeInTheDocument(); + expect(screen.getByText(/100/i)).toBeInTheDocument(); + }); +}); diff --git a/src/components/OrganizationDashCards/DashboardCard.tsx b/src/components/OrganizationDashCards/DashboardCard.tsx new file mode 100644 index 0000000000..4ad8fe8849 --- /dev/null +++ b/src/components/OrganizationDashCards/DashboardCard.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { Card, Row } from 'react-bootstrap'; +import Col from 'react-bootstrap/Col'; +import styles from './Dashboardcard.module.css'; + +const dashBoardCard = (props: { + icon: React.ReactNode; + title: string; + count?: number; +}): JSX.Element => { + const { icon, count, title } = props; + return ( + + + + +
    +
    + {icon} +
    + + + {count ?? 0} + {title} + + + + + ); +}; + +export default dashBoardCard; diff --git a/src/components/OrganizationDashCards/DashboardCardLoading.tsx b/src/components/OrganizationDashCards/DashboardCardLoading.tsx new file mode 100644 index 0000000000..5b596f32b2 --- /dev/null +++ b/src/components/OrganizationDashCards/DashboardCardLoading.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { Card, Row } from 'react-bootstrap'; +import Col from 'react-bootstrap/Col'; +import styles from './Dashboardcard.module.css'; + +const dashBoardCardLoading = (): JSX.Element => { + return ( + + + + +
    +
    +
    + + + + + + + + + ); +}; + +export default dashBoardCardLoading; diff --git a/src/components/OrganizationDashCards/Dashboardcard.module.css b/src/components/OrganizationDashCards/Dashboardcard.module.css new file mode 100644 index 0000000000..365657fb4f --- /dev/null +++ b/src/components/OrganizationDashCards/Dashboardcard.module.css @@ -0,0 +1,60 @@ +.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); +} + +@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; + } +} diff --git a/src/components/OrganizationScreen/OrganizationScreen.module.css b/src/components/OrganizationScreen/OrganizationScreen.module.css new file mode 100644 index 0000000000..9b8190a3ad --- /dev/null +++ b/src/components/OrganizationScreen/OrganizationScreen.module.css @@ -0,0 +1,178 @@ +.pageContainer { + display: flex; + flex-direction: column; + min-height: 100vh; + padding: 1rem 1.5rem 0 calc(300px + 2rem + 1.5rem); +} + +.expand { + padding-left: 4rem; + animation: moveLeft 0.5s ease-in-out; +} +.avatarStyle { + border-radius: 100%; +} +.profileContainer { + border: none; + padding: 2.1rem 0.5rem; + height: 52px; + border-radius: 8px 0px 0px 8px; + display: flex; + align-items: center; + background-color: white !important; + box-shadow: + 0 4px 4px 0 rgba(177, 177, 177, 0.2), + 0 6px 20px 0 rgba(151, 151, 151, 0.19); +} +.profileContainer:focus { + outline: none; + background-color: var(--bs-gray-100); +} +.imageContainer { + width: 56px; +} +.profileContainer .profileText { + flex: 1; + text-align: start; + overflow: hidden; + margin-right: 4px; +} +.angleDown { + margin-left: 4px; +} +.profileContainer .profileText .primaryText { + font-size: 1rem; + font-weight: 600; + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 2; /* number of lines to show */ + -webkit-box-orient: vertical; + word-wrap: break-word; + white-space: normal; +} +.profileContainer .profileText .secondaryText { + font-size: 0.8rem; + font-weight: 400; + color: var(--bs-secondary); + display: block; + text-transform: capitalize; +} + +.contract { + padding-left: calc(300px + 2rem + 1.5rem); + animation: moveRight 0.5s ease-in-out; +} + +.collapseSidebarButton { + position: fixed; + height: 40px; + bottom: 0; + z-index: 9999; + width: calc(300px + 2rem); + background-color: rgba(245, 245, 245, 0.7); + color: black; + border: none; + border-radius: 0px; +} + +.collapseSidebarButton:hover, +.opendrawer:hover { + opacity: 1; + color: black !important; +} +.opendrawer { + position: fixed; + display: flex; + align-items: center; + justify-content: center; + top: 0; + left: 0; + width: 40px; + height: 100vh; + z-index: 9999; + background-color: rgba(245, 245, 245); + border: none; + border-radius: 0px; + margin-right: 20px; + color: black; +} +.profileDropdown { + background-color: transparent !important; +} +.profileDropdown .dropdown-toggle .btn .btn-normal { + display: none !important; + background-color: transparent !important; +} +.dropdownToggle { + background-image: url(/public/images/svg/angleDown.svg); + background-repeat: no-repeat; + background-position: center; + background-color: azure; +} + +.dropdownToggle::after { + border-top: none !important; + border-bottom: none !important; +} + +.opendrawer:hover { + transition: background-color 0.5s ease; + background-color: var(--bs-primary); +} +.collapseSidebarButton:hover { + transition: background-color 0.5s ease; + background-color: var(--bs-primary); +} + +@media (max-width: 1120px) { + .contract { + padding-left: calc(276px + 2rem + 1.5rem); + } + .collapseSidebarButton { + width: calc(250px + 2rem); + } +} + +@media (max-height: 900px) { + .pageContainer { + padding: 1rem 1.5rem 0 calc(300px + 2rem); + } + .collapseSidebarButton { + height: 30px; + width: calc(300px + 1rem); + } +} +@media (max-height: 650px) { + .pageContainer { + padding: 1rem 1.5rem 0 calc(270px); + } + .collapseSidebarButton { + width: 250px; + height: 20px; + } + .opendrawer { + width: 30px; + } +} + +/* For tablets */ +@media (max-width: 820px) { + .pageContainer { + padding-left: 2.5rem; + } + + .opendrawer { + width: 25px; + } + + .contract, + .expand { + animation: none; + } + + .collapseSidebarButton { + width: 100%; + left: 0; + right: 0; + } +} diff --git a/src/components/OrganizationScreen/OrganizationScreen.test.tsx b/src/components/OrganizationScreen/OrganizationScreen.test.tsx new file mode 100644 index 0000000000..d31511ea1e --- /dev/null +++ b/src/components/OrganizationScreen/OrganizationScreen.test.tsx @@ -0,0 +1,117 @@ +import React from 'react'; +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 { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; +import OrganizationScreen from './OrganizationScreen'; +import { ORGANIZATIONS_LIST } from 'GraphQl/Queries/Queries'; +import { StaticMockLink } from 'utils/StaticMockLink'; + +let mockID: string | undefined = '123'; +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: mockID }), +})); + +const MOCKS = [ + { + request: { + query: ORGANIZATIONS_LIST, + variables: { id: '123' }, + }, + result: { + data: { + organizations: [ + { + _id: '123', + image: null, + creator: { + firstName: 'John', + lastName: 'Doe', + email: 'JohnDoe@example.com', + }, + name: 'Test Organization', + description: 'Testing this organization', + address: { + city: 'Mountain View', + countryCode: 'US', + dependentLocality: 'Some Dependent Locality', + line1: '123 Main Street', + line2: 'Apt 456', + postalCode: '94040', + sortingCode: 'XYZ-789', + state: 'CA', + }, + userRegistrationRequired: true, + visibleInSearch: true, + members: [], + admins: [], + membershipRequests: [], + blockedUsers: [], + }, + ], + }, + }, + }, +]; +const link = new StaticMockLink(MOCKS, true); + +const resizeWindow = (width: number): void => { + window.innerWidth = width; + fireEvent(window, new Event('resize')); +}; + +const clickToggleMenuBtn = (toggleButton: HTMLElement): void => { + fireEvent.click(toggleButton); +}; + +describe('Testing LeftDrawer in OrganizationScreen', () => { + test('Testing LeftDrawer in page functionality', async () => { + render( + + + + + + + + + , + ); + const toggleButton = screen.getByTestId('closeMenu') as HTMLElement; + const icon = toggleButton.querySelector('i'); + + // Resize window to a smaller width + resizeWindow(800); + clickToggleMenuBtn(toggleButton); + expect(icon).toHaveClass('fa fa-angle-double-left'); + // Resize window back to a larger width + + resizeWindow(1000); + clickToggleMenuBtn(toggleButton); + expect(icon).toHaveClass('fa fa-angle-double-right'); + + clickToggleMenuBtn(toggleButton); + expect(icon).toHaveClass('fa fa-angle-double-left'); + }); + + test('should be redirected to / if orgId is undefined', async () => { + mockID = undefined; + render( + + + + + + + + + , + ); + expect(window.location.pathname).toEqual('/'); + }); +}); diff --git a/src/components/OrganizationScreen/OrganizationScreen.tsx b/src/components/OrganizationScreen/OrganizationScreen.tsx new file mode 100644 index 0000000000..a8f9d16b9c --- /dev/null +++ b/src/components/OrganizationScreen/OrganizationScreen.tsx @@ -0,0 +1,126 @@ +import LeftDrawerOrg from 'components/LeftDrawerOrg/LeftDrawerOrg'; +import React, { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useDispatch, useSelector } from 'react-redux'; +import { Navigate, Outlet, useLocation, useParams } from 'react-router-dom'; +import { updateTargets } from 'state/action-creators'; +import type { RootState } from 'state/reducers'; +import type { TargetsType } from 'state/reducers/routesReducer'; +import styles from './OrganizationScreen.module.css'; +import ProfileDropdown from 'components/ProfileDropdown/ProfileDropdown'; +import { Button } from 'react-bootstrap'; + +const OrganizationScreen = (): JSX.Element => { + const location = useLocation(); + const titleKey: string | undefined = map[location.pathname.split('/')[1]]; + const { t } = useTranslation('translation', { keyPrefix: titleKey }); + const [hideDrawer, setHideDrawer] = useState(null); + const { orgId } = useParams(); + + if (!orgId) { + return ; + } + + const appRoutes: { + targets: TargetsType[]; + } = useSelector((state: RootState) => state.appRoutes); + const { targets } = appRoutes; + + const dispatch = useDispatch(); + useEffect(() => { + dispatch(updateTargets(orgId)); + }, [orgId]); // Added orgId to the dependency array + + const handleResize = (): void => { + if (window.innerWidth <= 820) { + setHideDrawer(!hideDrawer); + } + }; + + useEffect(() => { + handleResize(); + window.addEventListener('resize', handleResize); + return () => { + window.removeEventListener('resize', handleResize); + }; + }, []); + + return ( + <> + {hideDrawer ? ( + + ) : ( + + )} +
    + +
    +
    +
    +
    +

    {t('title')}

    +
    + +
    + +
    + + ); +}; + +export default OrganizationScreen; + +interface InterfaceMapType { + [key: string]: string; +} + +const map: InterfaceMapType = { + orgdash: 'dashboard', + orgpeople: 'organizationPeople', + requests: 'requests', + orgads: 'advertisement', + member: 'memberDetail', + orgevents: 'organizationEvents', + orgactionitems: 'organizationActionItems', + orgagendacategory: 'organizationAgendaCategory', + orgcontribution: 'orgContribution', + orgpost: 'orgPost', + orgfunds: 'funds', + orgfundcampaign: 'fundCampaign', + fundCampaignPledge: 'pledges', + orgsetting: 'orgSettings', + orgstore: 'addOnStore', + blockuser: 'blockUnblockUser', + orgvenues: 'organizationVenues', + event: 'eventManagement', +}; diff --git a/src/components/Pagination/Pagination.test.tsx b/src/components/Pagination/Pagination.test.tsx new file mode 100644 index 0000000000..b8161c4c84 --- /dev/null +++ b/src/components/Pagination/Pagination.test.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { createTheme, ThemeProvider } from '@mui/material/styles'; +import Pagination from './Pagination'; +import { store } from 'state/store'; +import userEvent from '@testing-library/user-event'; + +describe('Testing Pagination component', () => { + const props = { + count: 5, + page: 10, + rowsPerPage: 5, + onPageChange: (): number => { + return 10; + }, + }; + + test('Component should be rendered properly on rtl', () => { + render( + + + + + , + ); + + userEvent.click(screen.getByTestId(/nextPage/i)); + userEvent.click(screen.getByTestId(/previousPage/i)); + }); +}); + +const props = { + count: 5, + page: 10, + rowsPerPage: 5, + onPageChange: (): number => { + return 10; + }, + theme: { direction: 'rtl' }, +}; + +test('Component should be rendered properly', () => { + const theme = createTheme({ + direction: 'rtl', + }); + + render( + + + + + + + , + ); + + userEvent.click(screen.getByTestId(/nextPage/i)); + userEvent.click(screen.getByTestId(/previousPage/i)); +}); diff --git a/src/components/Pagination/Pagination.tsx b/src/components/Pagination/Pagination.tsx new file mode 100644 index 0000000000..ce7192e2a4 --- /dev/null +++ b/src/components/Pagination/Pagination.tsx @@ -0,0 +1,97 @@ +import React from 'react'; +import { useTheme } from '@mui/material/styles'; +import Box from '@mui/material/Box'; +import IconButton from '@mui/material/IconButton'; +import FirstPageIcon from '@mui/icons-material/FirstPage'; +import KeyboardArrowLeft from '@mui/icons-material/KeyboardArrowLeft'; +import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight'; +import LastPageIcon from '@mui/icons-material/LastPage'; + +interface InterfaceTablePaginationActionsProps { + count: number; + page: number; + rowsPerPage: number; + onPageChange: ( + event: React.MouseEvent, + newPage: number, + ) => void; +} + +function pagination(props: InterfaceTablePaginationActionsProps): JSX.Element { + const theme = useTheme(); + const { count, page, rowsPerPage, onPageChange } = props; + + /* istanbul ignore next */ + const handleFirstPageButtonClick = ( + event: React.MouseEvent, + ): void => { + onPageChange(event, 0); + }; + + const handleBackButtonClick = ( + event: React.MouseEvent, + ): void => { + onPageChange(event, page - 1); + }; + + /* istanbul ignore next */ + const handleNextButtonClick = ( + event: React.MouseEvent, + ): void => { + onPageChange(event, page + 1); + }; + + /* istanbul ignore next */ + const handleLastPageButtonClick = ( + event: React.MouseEvent, + ): void => { + onPageChange(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1)); + }; + + return ( + + + {theme.direction === 'rtl' ? : } + + + {theme.direction === 'rtl' ? ( + + ) : ( + + )} + + = Math.ceil(count / rowsPerPage) - 1} + aria-label="next page" + data-testid="nextPage" + > + {theme.direction === 'rtl' ? ( + + ) : ( + + )} + + = Math.ceil(count / rowsPerPage) - 1} + aria-label="last page" + data-testid="lastPage" + > + {theme.direction === 'rtl' ? : } + + + ); +} + +export default pagination; diff --git a/src/components/PaginationList/PaginationList.css b/src/components/PaginationList/PaginationList.css new file mode 100644 index 0000000000..2354c9a5f9 --- /dev/null +++ b/src/components/PaginationList/PaginationList.css @@ -0,0 +1,7 @@ +.MuiTablePagination-selectLabel { + margin-top: 1rem; +} + +.MuiTablePagination-displayedRows { + margin-top: 1rem; +} diff --git a/src/components/PaginationList/PaginationList.tsx b/src/components/PaginationList/PaginationList.tsx new file mode 100644 index 0000000000..3c0928f7fb --- /dev/null +++ b/src/components/PaginationList/PaginationList.tsx @@ -0,0 +1,81 @@ +import React from 'react'; +import { Hidden, TablePagination } from '@mui/material'; +import { useTranslation } from 'react-i18next'; + +import Pagination from '../Pagination/Pagination'; +import './PaginationList.css'; + +interface InterfacePropsInterface { + count: number; + rowsPerPage: number; + page: number; + onPageChange: ( + event: React.MouseEvent | null, + newPage: number, + ) => void; + onRowsPerPageChange: ( + event: React.ChangeEvent, + ) => void; +} + +const PaginationList = (props: InterfacePropsInterface): JSX.Element => { + const { t } = useTranslation('translation', { + keyPrefix: 'paginationList', + }); + + return ( + <> + + + + + + + + ); +}; + +export default PaginationList; diff --git a/src/components/ProfileDropdown/ProfileDropdown.module.css b/src/components/ProfileDropdown/ProfileDropdown.module.css new file mode 100644 index 0000000000..46af582126 --- /dev/null +++ b/src/components/ProfileDropdown/ProfileDropdown.module.css @@ -0,0 +1,75 @@ +.profileContainer { + border: none; + padding: 2.1rem 0.5rem; + height: 52px; + border-radius: 8px 0px 0px 8px; + display: flex; + align-items: center; + background-color: white !important; + box-shadow: + 0 4px 4px 0 rgba(177, 177, 177, 0.2), + 0 6px 44px 0 rgba(246, 246, 246, 0.19); +} +.profileContainer:focus { + outline: none; + background-color: var(--bs-gray-100); +} +.imageContainer { + width: 56px; + height: 56px; + border-radius: 100%; + margin-right: 10px; +} +.imageContainer img { + width: 100%; + height: 100%; + object-fit: cover; + border-radius: 100%; +} +.profileContainer .profileText { + flex: 1; + text-align: start; + overflow: hidden; + margin-right: 4px; +} +.angleDown { + margin-left: 4px; +} +.profileContainer .profileText .primaryText { + font-size: 1rem; + font-weight: 600; + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 2; /* number of lines to show */ + -webkit-box-orient: vertical; + word-wrap: break-word; + white-space: normal; +} +.profileContainer .profileText .secondaryText { + font-size: 0.8rem; + font-weight: 400; + color: var(--bs-secondary); + display: block; + text-transform: capitalize; +} +.profileDropdown { + background-color: transparent !important; +} +.profileDropdown .dropdown-toggle .btn .btn-normal { + display: none !important; + background-color: transparent !important; +} +.dropdownToggle { + background-image: url(/public/images/svg/angleDown.svg); + background-repeat: no-repeat; + background-position: center; + background-color: azure; +} + +.dropdownToggle::after { + border-top: none !important; + border-bottom: none !important; +} +.avatarStyle { + border-radius: 100%; +} diff --git a/src/components/ProfileDropdown/ProfileDropdown.test.tsx b/src/components/ProfileDropdown/ProfileDropdown.test.tsx new file mode 100644 index 0000000000..0efef50591 --- /dev/null +++ b/src/components/ProfileDropdown/ProfileDropdown.test.tsx @@ -0,0 +1,131 @@ +import React from 'react'; +import { act, render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { BrowserRouter } from 'react-router-dom'; +import ProfileDropdown from './ProfileDropdown'; +import 'jest-localstorage-mock'; +import { MockedProvider } from '@apollo/react-testing'; +import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; +import useLocalStorage from 'utils/useLocalstorage'; +import { I18nextProvider } from 'react-i18next'; +import i18nForTest from 'utils/i18nForTest'; + +const { setItem } = useLocalStorage(); +const MOCKS = [ + { + request: { + query: REVOKE_REFRESH_TOKEN, + }, + result: { + data: { + revokeRefreshTokenForUser: true, + }, + }, + }, +]; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }, + clear: jest.fn(), +})); + +beforeEach(() => { + setItem('FirstName', 'John'); + setItem('LastName', 'Doe'); + setItem( + 'UserImage', + 'https://api.dicebear.com/5.x/initials/svg?seed=John%20Doe', + ); + setItem('SuperAdmin', false); + setItem('AdminFor', []); + setItem('id', '123'); +}); + +afterEach(() => { + jest.clearAllMocks(); + localStorage.clear(); +}); +afterEach(() => { + jest.clearAllMocks(); + localStorage.clear(); +}); + +describe('ProfileDropdown Component', () => { + test('renders with user information', () => { + render( + + + + + + + , + ); + + expect(screen.getByTestId('display-name')).toBeInTheDocument(); + expect(screen.getByText('John Doe')).toBeInTheDocument(); + expect(screen.getByText('User')).toBeInTheDocument(); + expect(screen.getByTestId('display-type')).toBeInTheDocument(); + expect(screen.getByAltText('profile picture')).toBeInTheDocument(); + }); + + test('renders Super admin', () => { + setItem('SuperAdmin', true); + render( + + + + + , + ); + expect(screen.getByText('SuperAdmin')).toBeInTheDocument(); + }); + test('renders Admin', () => { + setItem('AdminFor', ['123']); + render( + + + + + , + ); + expect(screen.getByText('Admin')).toBeInTheDocument(); + }); + + test('logout functionality clears local storage and redirects to home', async () => { + render( + + + + + , + ); + await act(async () => { + userEvent.click(screen.getByTestId('togDrop')); + }); + + userEvent.click(screen.getByTestId('logoutBtn')); + expect(global.window.location.pathname).toBe('/'); + }); + describe('Member screen routing testing', () => { + test('member screen', async () => { + render( + + + + + , + ); + await act(async () => { + userEvent.click(screen.getByTestId('togDrop')); + }); + + userEvent.click(screen.getByTestId('profileBtn')); + expect(global.window.location.pathname).toBe('/user/settings'); + }); + }); +}); diff --git a/src/components/ProfileDropdown/ProfileDropdown.tsx b/src/components/ProfileDropdown/ProfileDropdown.tsx new file mode 100644 index 0000000000..28c96a988c --- /dev/null +++ b/src/components/ProfileDropdown/ProfileDropdown.tsx @@ -0,0 +1,109 @@ +import Avatar from 'components/Avatar/Avatar'; +import React from 'react'; +import { ButtonGroup, Dropdown } from 'react-bootstrap'; +import { useNavigate } from 'react-router-dom'; +import useLocalStorage from 'utils/useLocalstorage'; +import styles from './ProfileDropdown.module.css'; +import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; +import { useMutation } from '@apollo/client'; +import { useTranslation } from 'react-i18next'; + +const profileDropdown = (): JSX.Element => { + const { t: tCommon } = useTranslation('common'); + const [revokeRefreshToken] = useMutation(REVOKE_REFRESH_TOKEN); + const { getItem } = useLocalStorage(); + const superAdmin = getItem('SuperAdmin'); + const adminFor = getItem('AdminFor'); + const userRole = superAdmin + ? 'SuperAdmin' + : adminFor?.length > 0 + ? 'Admin' + : 'User'; + const firstName = getItem('FirstName'); + const lastName = getItem('LastName'); + const userImage = getItem('UserImage'); + const userID = getItem('id'); + const navigate = useNavigate(); + + const logout = async (): Promise => { + try { + await revokeRefreshToken(); + } catch (error) { + /*istanbul ignore next*/ + console.error('Error revoking refresh token:', error); + } + localStorage.clear(); + navigate('/'); + }; + const MAX_NAME_LENGTH = 20; + const fullName = `${firstName} ${lastName}`; + const displayedName = + fullName.length > MAX_NAME_LENGTH + ? /*istanbul ignore next*/ + fullName.substring(0, MAX_NAME_LENGTH - 3) + '...' + : fullName; + + return ( + +
    +
    + {userImage && userImage !== 'null' ? ( + /*istanbul ignore next*/ + {`profile + ) : ( + + )} +
    +
    + + {displayedName} + + + {`${userRole}`} + +
    +
    + + + + userRole === 'User' + ? navigate(`/user/settings`) + : navigate(`/member/${userID}`) + } + aria-label="View Profile" + > + {tCommon('viewProfile')} + + + {tCommon('logout')} + + +
    + ); +}; + +export default profileDropdown; diff --git a/src/components/RecurrenceOptions/CustomRecurrence.test.tsx b/src/components/RecurrenceOptions/CustomRecurrence.test.tsx new file mode 100644 index 0000000000..f21553c5af --- /dev/null +++ b/src/components/RecurrenceOptions/CustomRecurrence.test.tsx @@ -0,0 +1,721 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { + act, + render, + screen, + fireEvent, + waitFor, +} 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 OrganizationEvents from '../../screens/OrganizationEvents/OrganizationEvents'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; +import userEvent from '@testing-library/user-event'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { toast } from 'react-toastify'; +import { createTheme } from '@mui/material'; +import { ThemeProvider } from 'react-bootstrap'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { MOCKS } from '../../screens/OrganizationEvents/OrganizationEventsMocks'; + +const theme = createTheme({ + palette: { + primary: { + main: '#31bb6b', + }, + }, +}); + +const link = new StaticMockLink(MOCKS, true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const translations = JSON.parse( + JSON.stringify( + i18nForTest.getDataByLanguage('en')?.translation.organizationEvents, + ), +); + +jest.mock('@mui/x-date-pickers/DateTimePicker', () => { + return { + DateTimePicker: jest.requireActual( + '@mui/x-date-pickers/DesktopDateTimePicker', + ).DesktopDateTimePicker, + }; +}); + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + warning: jest.fn(), + error: jest.fn(), + }, +})); + +describe('Testing the creaction of recurring events with custom recurrence patterns', () => { + const formData = { + title: 'Dummy Org', + description: 'This is a dummy organization', + startDate: '03/28/2022', + endDate: '03/30/2022', + recurrenceEndDate: '04/15/2023', + location: 'New Delhi', + startTime: '09:00 AM', + endTime: '05:00 PM', + }; + + test('Changing the recurrence frequency', async () => { + render( + + + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createEventModalBtn')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('createEventModalBtn')); + + await waitFor(() => { + expect(screen.getByTestId('recurringCheck')).toBeInTheDocument(); + }); + + expect(screen.queryByTestId('recurrenceOptions')).not.toBeInTheDocument(); + + userEvent.click(screen.getByTestId('recurringCheck')); + + await waitFor(() => { + expect(screen.getByTestId('recurrenceOptions')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('recurrenceOptions')); + + await waitFor(() => { + expect(screen.getByTestId('customRecurrence')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('customRecurrence')); + + await waitFor(() => { + expect( + screen.getByTestId('customRecurrenceFrequencyDropdown'), + ).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('customRecurrenceFrequencyDropdown')); + + await waitFor(() => { + expect(screen.getByTestId('customDailyRecurrence')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('customDailyRecurrence')); + + await waitFor(() => { + expect( + screen.getByTestId('customRecurrenceFrequencyDropdown'), + ).toHaveTextContent('Day'); + }); + + userEvent.click(screen.getByTestId('customRecurrenceFrequencyDropdown')); + + await waitFor(() => { + expect(screen.getByTestId('customWeeklyRecurrence')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('customWeeklyRecurrence')); + + await waitFor(() => { + expect( + screen.getByTestId('customRecurrenceFrequencyDropdown'), + ).toHaveTextContent('Week'); + }); + + userEvent.click(screen.getByTestId('customRecurrenceFrequencyDropdown')); + + await waitFor(() => { + expect(screen.getByTestId('customMonthlyRecurrence')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('customMonthlyRecurrence')); + + await waitFor(() => { + expect( + screen.getByTestId('customRecurrenceFrequencyDropdown'), + ).toHaveTextContent('Month'); + }); + + userEvent.click(screen.getByTestId('customRecurrenceFrequencyDropdown')); + + await waitFor(() => { + expect(screen.getByTestId('customYearlyRecurrence')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('customYearlyRecurrence')); + + await waitFor(() => { + expect( + screen.getByTestId('customRecurrenceFrequencyDropdown'), + ).toHaveTextContent('Year'); + }); + + userEvent.click(screen.getByTestId('customRecurrenceSubmitBtn')); + await waitFor(() => { + expect( + screen.queryByTestId('customRecurrenceSubmitBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('Selecting and unselecting recurrence weekdays', async () => { + render( + + + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createEventModalBtn')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('createEventModalBtn')); + + await waitFor(() => { + expect(screen.getByTestId('recurringCheck')).toBeInTheDocument(); + }); + + expect(screen.queryByTestId('recurrenceOptions')).not.toBeInTheDocument(); + + userEvent.click(screen.getByTestId('recurringCheck')); + + await waitFor(() => { + expect(screen.getByTestId('recurrenceOptions')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('recurrenceOptions')); + + await waitFor(() => { + expect(screen.getByTestId('customRecurrence')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('customRecurrence')); + + await waitFor(() => { + expect( + screen.getByTestId('customRecurrenceSubmitBtn'), + ).toBeInTheDocument(); + }); + + const weekDaysOptions = screen.getAllByTestId('recurrenceWeekDay'); + + weekDaysOptions.forEach((weekDay) => { + userEvent.click(weekDay); + }); + + weekDaysOptions.forEach((weekDay) => { + userEvent.click(weekDay); + }); + + userEvent.click(screen.getByTestId('customRecurrenceSubmitBtn')); + await waitFor(() => { + expect( + screen.queryByTestId('customRecurrenceSubmitBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('Selecting different monthly recurrence options from the dropdown menu', async () => { + render( + + + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createEventModalBtn')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('createEventModalBtn')); + + const startDatePicker = screen.getByLabelText('Start Date'); + fireEvent.change(startDatePicker, { + target: { value: formData.startDate }, + }); + + const endDatePicker = screen.getByLabelText('End Date'); + fireEvent.change(endDatePicker, { + target: { value: formData.endDate }, + }); + + await waitFor(() => { + expect(screen.getByTestId('recurringCheck')).toBeInTheDocument(); + }); + + expect(screen.queryByTestId('recurrenceOptions')).not.toBeInTheDocument(); + + userEvent.click(screen.getByTestId('recurringCheck')); + + await waitFor(() => { + expect(screen.getByTestId('recurrenceOptions')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('recurrenceOptions')); + + await waitFor(() => { + expect(screen.getByTestId('customRecurrence')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('customRecurrence')); + + await waitFor(() => { + expect( + screen.getByTestId('customRecurrenceFrequencyDropdown'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('customRecurrenceFrequencyDropdown')); + + await waitFor(() => { + expect(screen.getByTestId('customMonthlyRecurrence')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('customMonthlyRecurrence')); + + await waitFor(() => { + expect( + screen.getByTestId('customRecurrenceFrequencyDropdown'), + ).toHaveTextContent('Month'); + }); + + await waitFor(() => { + expect(screen.getByTestId('monthlyRecurrenceOptions')).toHaveTextContent( + 'Monthly on Day 28', + ); + }); + + userEvent.click(screen.getByTestId('monthlyRecurrenceOptions')); + + await waitFor(() => { + expect( + screen.getByTestId('monthlyRecurrenceOptionOnThatOccurence'), + ).toBeInTheDocument(); + }); + userEvent.click( + screen.getByTestId('monthlyRecurrenceOptionOnThatOccurence'), + ); + + await waitFor(() => { + expect(screen.getByTestId('monthlyRecurrenceOptions')).toHaveTextContent( + 'Monthly on Fourth Monday', + ); + }); + + userEvent.click(screen.getByTestId('monthlyRecurrenceOptions')); + + await waitFor(() => { + expect( + screen.getByTestId('monthlyRecurrenceOptionOnLastOccurence'), + ).toBeInTheDocument(); + }); + userEvent.click( + screen.getByTestId('monthlyRecurrenceOptionOnLastOccurence'), + ); + + await waitFor(() => { + expect(screen.getByTestId('monthlyRecurrenceOptions')).toHaveTextContent( + 'Monthly on Last Monday', + ); + }); + + userEvent.click(screen.getByTestId('monthlyRecurrenceOptions')); + + await waitFor(() => { + expect( + screen.getByTestId('monthlyRecurrenceOptionOnThatDay'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('monthlyRecurrenceOptionOnThatDay')); + + await waitFor(() => { + expect(screen.getByTestId('monthlyRecurrenceOptions')).toHaveTextContent( + 'Monthly on Day 28', + ); + }); + }); + + test('Selecting the "Ends on" option for specifying the end of recurrence', async () => { + // i.e. when would the recurring event end: never, on a certain date, or after a certain number of occurences + render( + + + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createEventModalBtn')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('createEventModalBtn')); + + await waitFor(() => { + expect(screen.getByTestId('recurringCheck')).toBeInTheDocument(); + }); + + expect(screen.queryByTestId('recurrenceOptions')).not.toBeInTheDocument(); + + userEvent.click(screen.getByTestId('recurringCheck')); + + await waitFor(() => { + expect(screen.getByTestId('recurrenceOptions')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('recurrenceOptions')); + + await waitFor(() => { + expect(screen.getByTestId('customRecurrence')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('customRecurrence')); + + await waitFor(() => { + expect(screen.getByTestId('never')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('never')); + userEvent.click(screen.getByTestId('on')); + userEvent.click(screen.getByTestId('after')); + userEvent.click(screen.getByTestId('never')); + + userEvent.click(screen.getByTestId('customRecurrenceSubmitBtn')); + await waitFor(() => { + expect( + screen.queryByTestId('customRecurrenceSubmitBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('Creating a bi monthly recurring event through custom recurrence modal', async () => { + render( + + + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createEventModalBtn')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('createEventModalBtn')); + + await waitFor(() => { + expect(screen.getByPlaceholderText(/Enter Title/i)).toBeInTheDocument(); + }); + + userEvent.type(screen.getByPlaceholderText(/Enter Title/i), formData.title); + + userEvent.type( + screen.getByPlaceholderText(/Enter Description/i), + formData.description, + ); + + userEvent.type( + screen.getByPlaceholderText(/Enter Location/i), + formData.location, + ); + + const startDatePicker = screen.getByLabelText('Start Date'); + fireEvent.change(startDatePicker, { + target: { value: formData.startDate }, + }); + + const eventEndDatePicker = screen.getByLabelText('End Date'); + fireEvent.change(eventEndDatePicker, { + target: { value: formData.endDate }, + }); + + userEvent.click(screen.getByTestId('recurringCheck')); + + await waitFor(() => { + expect(screen.getByTestId('recurrenceOptions')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('recurrenceOptions')); + + await waitFor(() => { + expect(screen.getByTestId('customRecurrence')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('customRecurrence')); + + userEvent.click(screen.getByTestId('customRecurrenceFrequencyDropdown')); + + await waitFor(() => { + expect(screen.getByTestId('customMonthlyRecurrence')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('customMonthlyRecurrence')); + + await waitFor(() => { + expect( + screen.getByTestId('customRecurrenceFrequencyDropdown'), + ).toHaveTextContent('Month'); + }); + + userEvent.click(screen.getByTestId('monthlyRecurrenceOptions')); + + await waitFor(() => { + expect( + screen.getByTestId('monthlyRecurrenceOptionOnThatOccurence'), + ).toBeInTheDocument(); + }); + userEvent.click( + screen.getByTestId('monthlyRecurrenceOptionOnThatOccurence'), + ); + + await waitFor(() => { + expect(screen.getByTestId('on')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('on')); + + await waitFor(() => { + expect(screen.getByTestId('on')).toBeChecked(); + }); + + await waitFor(() => { + expect(screen.getAllByLabelText('End Date')[1]).toBeEnabled(); + }); + + const recurrenceEndDatePicker = screen.getAllByLabelText('End Date')[1]; + fireEvent.change(recurrenceEndDatePicker, { + target: { value: formData.recurrenceEndDate }, + }); + + await waitFor(() => { + expect( + screen.getByTestId('customRecurrenceIntervalInput'), + ).toBeInTheDocument(); + }); + + const recurrenceCount = screen.getByTestId('customRecurrenceIntervalInput'); + fireEvent.change(recurrenceCount, { + target: { value: 2 }, + }); + + userEvent.click(screen.getByTestId('customRecurrenceSubmitBtn')); + await waitFor(() => { + expect( + screen.queryByTestId('customRecurrenceSubmitBtn'), + ).not.toBeInTheDocument(); + }); + + expect(screen.getByTestId('recurrenceOptions')).toHaveTextContent( + 'Every 2 months on Fourth Monday, until April...', + // "..." because of the overlay component that would trim the recurrence rule text at 45 characters + ); + + userEvent.click(screen.getByTestId('createEventBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.eventCreated); + }); + + await waitFor(() => { + expect( + screen.queryByTestId('createEventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('Creating a daily recurring event with a certain number of occurences', async () => { + render( + + + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createEventModalBtn')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('createEventModalBtn')); + + await waitFor(() => { + expect(screen.getByPlaceholderText(/Enter Title/i)).toBeInTheDocument(); + }); + + userEvent.type(screen.getByPlaceholderText(/Enter Title/i), formData.title); + + userEvent.type( + screen.getByPlaceholderText(/Enter Description/i), + formData.description, + ); + + userEvent.type( + screen.getByPlaceholderText(/Enter Location/i), + formData.location, + ); + + const startDatePicker = screen.getByLabelText('Start Date'); + const endDatePicker = screen.getByLabelText('End Date'); + + fireEvent.change(startDatePicker, { + target: { value: formData.startDate }, + }); + + fireEvent.change(endDatePicker, { + target: { value: formData.endDate }, + }); + + userEvent.click(screen.getByTestId('recurringCheck')); + + await waitFor(() => { + expect(screen.getByTestId('recurrenceOptions')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('recurrenceOptions')); + + await waitFor(() => { + expect(screen.getByTestId('customRecurrence')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('customRecurrence')); + + userEvent.click(screen.getByTestId('customRecurrenceFrequencyDropdown')); + + await waitFor(() => { + expect(screen.getByTestId('customDailyRecurrence')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('customDailyRecurrence')); + + await waitFor(() => { + expect( + screen.getByTestId('customRecurrenceFrequencyDropdown'), + ).toHaveTextContent('Day'); + }); + + await waitFor(() => { + expect(screen.getByTestId('after')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('after')); + + await waitFor(() => { + expect(screen.getByTestId('after')).toBeChecked(); + }); + + await waitFor(() => { + expect( + screen.getByTestId('customRecurrenceCountInput'), + ).toBeInTheDocument(); + }); + + const recurrenceCount = screen.getByTestId('customRecurrenceCountInput'); + fireEvent.change(recurrenceCount, { + target: { value: 100 }, + }); + + await waitFor(() => { + expect(screen.getByTestId('customRecurrenceCountInput')).toHaveValue(100); + }); + + userEvent.click(screen.getByTestId('customRecurrenceSubmitBtn')); + await waitFor(() => { + expect( + screen.queryByTestId('customRecurrenceSubmitBtn'), + ).not.toBeInTheDocument(); + }); + + expect(screen.getByTestId('recurrenceOptions')).toHaveTextContent( + 'Daily, 100 times', + ); + + userEvent.click(screen.getByTestId('createEventBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.eventCreated); + }); + + await waitFor(() => { + expect( + screen.queryByTestId('createEventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); +}); diff --git a/src/components/RecurrenceOptions/CustomRecurrenceModal.module.css b/src/components/RecurrenceOptions/CustomRecurrenceModal.module.css new file mode 100644 index 0000000000..5fe5d33c47 --- /dev/null +++ b/src/components/RecurrenceOptions/CustomRecurrenceModal.module.css @@ -0,0 +1,59 @@ +.titlemodal { + color: #707070; + font-weight: 600; + font-size: 20px; + margin-bottom: 20px; + padding-bottom: 5px; + border-bottom: 3px solid #31bb6b; + width: 65%; +} + +.recurrenceRuleNumberInput { + width: 70px; +} + +.recurrenceRuleDateBox { + width: 70%; +} + +.recurrenceDayButton { + width: 33px; + height: 33px; + border: 1px solid var(--bs-gray); + cursor: pointer; + transition: background-color 0.3s; + display: inline-flex; + justify-content: center; + align-items: center; + margin-right: 0.5rem; + border-radius: 50%; +} + +.recurrenceDayButton:hover { + background-color: var(--bs-gray); +} + +.recurrenceDayButton.selected { + background-color: var(--bs-primary); + border-color: var(--bs-primary); + color: var(--bs-white); +} + +.recurrenceDayButton span { + color: var(--bs-gray); + padding: 0.25rem; + text-align: center; +} + +.recurrenceDayButton:hover span { + color: var(--bs-white); +} + +.recurrenceDayButton.selected span { + color: var(--bs-white); +} + +.recurrenceRuleSubmitBtn { + margin-left: 82%; + padding: 7px 15px; +} diff --git a/src/components/RecurrenceOptions/CustomRecurrenceModal.tsx b/src/components/RecurrenceOptions/CustomRecurrenceModal.tsx new file mode 100644 index 0000000000..c1aecaa854 --- /dev/null +++ b/src/components/RecurrenceOptions/CustomRecurrenceModal.tsx @@ -0,0 +1,400 @@ +import React, { useEffect, useState } from 'react'; +import { Button, Dropdown, Form, FormControl, Modal } from 'react-bootstrap'; +import styles from './CustomRecurrenceModal.module.css'; +import { DatePicker } from '@mui/x-date-pickers'; +import { + Days, + Frequency, + daysOptions, + endsAfter, + endsNever, + endsOn, + frequencies, + getRecurrenceRuleText, + getWeekDayOccurenceInMonth, + isLastOccurenceOfWeekDay, + recurrenceEndOptions, +} from 'utils/recurrenceUtils'; +import type { + InterfaceRecurrenceRuleState, + RecurrenceEndOption, + WeekDays, +} from 'utils/recurrenceUtils'; +import type { Dayjs } from 'dayjs'; +import dayjs from 'dayjs'; + +interface InterfaceCustomRecurrenceModalProps { + recurrenceRuleState: InterfaceRecurrenceRuleState; + recurrenceRuleText: string; + setRecurrenceRuleState: ( + state: React.SetStateAction, + ) => void; + customRecurrenceModalIsOpen: boolean; + hideCustomRecurrenceModal: () => void; + setCustomRecurrenceModalIsOpen: ( + state: React.SetStateAction, + ) => void; + t: (key: string) => string; + tCommon: (key: string) => string; +} + +const CustomRecurrenceModal: React.FC = ({ + recurrenceRuleState, + recurrenceRuleText, + setRecurrenceRuleState, + customRecurrenceModalIsOpen, + hideCustomRecurrenceModal, + setCustomRecurrenceModalIsOpen, + t, + tCommon, +}) => { + const { + recurrenceStartDate, + recurrenceEndDate, + frequency, + weekDays, + interval, + count, + } = recurrenceRuleState; + const [selectedRecurrenceEndOption, setSelectedRecurrenceEndOption] = + useState(endsNever); + + useEffect(() => { + if (recurrenceEndDate) { + setSelectedRecurrenceEndOption(endsOn); + } else if (count) { + setSelectedRecurrenceEndOption(endsAfter); + } + }, [recurrenceRuleState]); + + const handleRecurrenceEndOptionChange = ( + e: React.ChangeEvent, + ): void => { + const selectedRecurrenceEndOption = e.target.value as RecurrenceEndOption; + setSelectedRecurrenceEndOption(selectedRecurrenceEndOption); + if (selectedRecurrenceEndOption === endsNever) { + setRecurrenceRuleState({ + ...recurrenceRuleState, + recurrenceEndDate: null, + count: undefined, + }); + } + if (selectedRecurrenceEndOption === endsOn) { + setRecurrenceRuleState({ + ...recurrenceRuleState, + recurrenceEndDate: dayjs().add(1, 'month').toDate(), + count: undefined, + }); + } + if (selectedRecurrenceEndOption === endsAfter) { + setRecurrenceRuleState({ + ...recurrenceRuleState, + recurrenceEndDate: null, + count: 10, + }); + } + }; + + const handleDayClick = (day: WeekDays): void => { + if (weekDays !== undefined && weekDays.includes(day)) { + setRecurrenceRuleState({ + ...recurrenceRuleState, + weekDays: weekDays.filter((d) => d !== day), + weekDayOccurenceInMonth: undefined, + }); + } else { + setRecurrenceRuleState({ + ...recurrenceRuleState, + weekDays: [...(weekDays ?? []), day], + weekDayOccurenceInMonth: undefined, + }); + } + }; + + const handleCustomRecurrenceSubmit = (): void => { + setCustomRecurrenceModalIsOpen(!customRecurrenceModalIsOpen); + }; + + return ( + <> + + +

    {t('customRecurrence')}

    + +
    + +
    + + {t('repeatsEvery')} + {' '} + + setRecurrenceRuleState({ + ...recurrenceRuleState, + interval: Number(e.target.value), + }) + } + /> + + + {`${frequencies[frequency]}${interval && interval > 1 ? 's' : ''}`} + + + + + setRecurrenceRuleState({ + ...recurrenceRuleState, + frequency: Frequency.DAILY, + weekDayOccurenceInMonth: undefined, + }) + } + data-testid="customDailyRecurrence" + > + {interval && interval > 1 ? 'Days' : 'Day'} + + + setRecurrenceRuleState({ + ...recurrenceRuleState, + frequency: Frequency.WEEKLY, + weekDays: [Days[recurrenceStartDate.getDay()]], + weekDayOccurenceInMonth: undefined, + }) + } + data-testid="customWeeklyRecurrence" + > + {interval && interval > 1 ? 'Weeks' : 'Week'} + + + setRecurrenceRuleState({ + ...recurrenceRuleState, + frequency: Frequency.MONTHLY, + weekDayOccurenceInMonth: undefined, + }) + } + data-testid="customMonthlyRecurrence" + > + {interval && interval > 1 ? 'Months' : 'Month'} + + + setRecurrenceRuleState({ + ...recurrenceRuleState, + frequency: Frequency.YEARLY, + weekDayOccurenceInMonth: undefined, + }) + } + data-testid="customYearlyRecurrence" + > + {interval && interval > 1 ? 'Years' : 'Year'} + + + +
    + + {frequency === Frequency.WEEKLY && ( +
    + + {t('repeatsOn')} + +
    +
    + {daysOptions.map((day, index) => ( +
    handleDayClick(Days[index])} + data-testid="recurrenceWeekDay" + > + {day} +
    + ))} +
    +
    + )} + + {frequency === Frequency.MONTHLY && ( +
    + + + {recurrenceRuleText} + + + + setRecurrenceRuleState({ + ...recurrenceRuleState, + frequency: Frequency.MONTHLY, + weekDayOccurenceInMonth: undefined, + }) + } + data-testid="monthlyRecurrenceOptionOnThatDay" + > + + {getRecurrenceRuleText({ + ...recurrenceRuleState, + frequency: Frequency.MONTHLY, + weekDayOccurenceInMonth: undefined, + })} + + + {getWeekDayOccurenceInMonth(recurrenceStartDate) !== 5 && ( + + setRecurrenceRuleState({ + ...recurrenceRuleState, + frequency: Frequency.MONTHLY, + weekDays: [Days[recurrenceStartDate.getDay()]], + weekDayOccurenceInMonth: + getWeekDayOccurenceInMonth(recurrenceStartDate), + }) + } + data-testid="monthlyRecurrenceOptionOnThatOccurence" + > + + {getRecurrenceRuleText({ + ...recurrenceRuleState, + frequency: Frequency.MONTHLY, + weekDays: [Days[recurrenceStartDate.getDay()]], + weekDayOccurenceInMonth: + getWeekDayOccurenceInMonth(recurrenceStartDate), + })} + + + )} + {isLastOccurenceOfWeekDay(recurrenceStartDate) && ( + + setRecurrenceRuleState({ + ...recurrenceRuleState, + frequency: Frequency.MONTHLY, + weekDays: [Days[recurrenceStartDate.getDay()]], + weekDayOccurenceInMonth: -1, + }) + } + data-testid="monthlyRecurrenceOptionOnLastOccurence" + > + + {getRecurrenceRuleText({ + ...recurrenceRuleState, + frequency: Frequency.MONTHLY, + weekDays: [Days[recurrenceStartDate.getDay()]], + weekDayOccurenceInMonth: -1, + })} + + + )} + + +
    + )} + +
    + {t('ends')} +
    +
    + {recurrenceEndOptions.map((option, index) => ( +
    + + + {option === endsOn && ( +
    + { + /* istanbul ignore next */ + if (date) { + setRecurrenceRuleState({ + ...recurrenceRuleState, + recurrenceEndDate: date?.toDate(), + }); + } + }} + /> +
    + )} + {option === endsAfter && ( + <> + + setRecurrenceRuleState({ + ...recurrenceRuleState, + count: Number(e.target.value), + }) + } + className={`${styles.recurrenceRuleNumberInput} ms-1 me-2 d-inline-block py-2`} + disabled={selectedRecurrenceEndOption !== endsAfter} + data-testid="customRecurrenceCountInput" + />{' '} + {t('occurences')} + + )} +
    + ))} +
    +
    +
    + +
    + +
    + +
    +
    +
    + + ); +}; + +export default CustomRecurrenceModal; diff --git a/src/components/RecurrenceOptions/RecurrenceOptions.test.tsx b/src/components/RecurrenceOptions/RecurrenceOptions.test.tsx new file mode 100644 index 0000000000..510f7a04aa --- /dev/null +++ b/src/components/RecurrenceOptions/RecurrenceOptions.test.tsx @@ -0,0 +1,587 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { + act, + render, + screen, + fireEvent, + waitFor, +} 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 OrganizationEvents from '../../screens/OrganizationEvents/OrganizationEvents'; +import { store } from 'state/store'; +import i18n from 'utils/i18nForTest'; +import userEvent from '@testing-library/user-event'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { toast } from 'react-toastify'; +import { createTheme } from '@mui/material'; +import { ThemeProvider } from 'react-bootstrap'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { MOCKS } from '../../screens/OrganizationEvents/OrganizationEventsMocks'; + +const theme = createTheme({ + palette: { + primary: { + main: '#31bb6b', + }, + }, +}); + +const link = new StaticMockLink(MOCKS, true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const translations = { + ...JSON.parse( + JSON.stringify( + i18n.getDataByLanguage('en')?.translation.organizationEvents ?? {}, + ), + ), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), +}; + +jest.mock('@mui/x-date-pickers/DateTimePicker', () => { + return { + DateTimePicker: jest.requireActual( + '@mui/x-date-pickers/DesktopDateTimePicker', + ).DesktopDateTimePicker, + }; +}); + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + warning: jest.fn(), + error: jest.fn(), + }, +})); + +describe('Testing the creaction of recurring events through recurrence options', () => { + const formData = { + title: 'Dummy Org', + description: 'This is a dummy organization', + startDate: '03/28/2022', + endDate: '03/30/2022', + location: 'New Delhi', + startTime: '09:00 AM', + endTime: '05:00 PM', + }; + + test('Recurrence options Dropdown shows up after checking the Recurring switch', async () => { + render( + + + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createEventModalBtn')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('createEventModalBtn')); + + await waitFor(() => { + expect(screen.getByTestId('recurringCheck')).toBeInTheDocument(); + }); + + expect(screen.queryByTestId('recurrenceOptions')).not.toBeInTheDocument(); + + userEvent.click(screen.getByTestId('recurringCheck')); + + await waitFor(() => { + expect(screen.getByTestId('recurrenceOptions')).toBeInTheDocument(); + }); + }); + + test('Showing different recurrence options through the Dropdown', async () => { + render( + + + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createEventModalBtn')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('createEventModalBtn')); + + await waitFor(() => { + expect(screen.getByTestId('recurringCheck')).toBeInTheDocument(); + }); + + expect(screen.queryByTestId('recurrenceOptions')).not.toBeInTheDocument(); + + userEvent.click(screen.getByTestId('recurringCheck')); + + await waitFor(() => { + expect(screen.getByTestId('recurrenceOptions')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('recurrenceOptions')); + + await waitFor(() => { + expect(screen.getByTestId('customRecurrence')).toBeInTheDocument(); + }); + }); + + test('Toggling of custom recurrence modal', async () => { + render( + + + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createEventModalBtn')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('createEventModalBtn')); + + await waitFor(() => { + expect(screen.getByTestId('recurringCheck')).toBeInTheDocument(); + }); + + expect(screen.queryByTestId('recurrenceOptions')).not.toBeInTheDocument(); + + userEvent.click(screen.getByTestId('recurringCheck')); + + await waitFor(() => { + expect(screen.getByTestId('recurrenceOptions')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('recurrenceOptions')); + + await waitFor(() => { + expect(screen.getByTestId('customRecurrence')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('customRecurrence')); + + await waitFor(() => { + expect( + screen.getByTestId('customRecurrenceModalCloseBtn'), + ).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('customRecurrenceModalCloseBtn')); + + await waitFor(() => { + expect( + screen.queryByTestId('customRecurrenceModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('Selecting different recurrence options from the dropdown menu', async () => { + render( + + + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createEventModalBtn')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('createEventModalBtn')); + + const startDatePicker = screen.getByLabelText('Start Date'); + const endDatePicker = screen.getByLabelText('End Date'); + + fireEvent.change(startDatePicker, { + target: { value: formData.startDate }, + }); + + fireEvent.change(endDatePicker, { + target: { value: formData.endDate }, + }); + + await waitFor(() => { + expect(screen.getByTestId('recurringCheck')).toBeInTheDocument(); + }); + + expect(screen.queryByTestId('recurrenceOptions')).not.toBeInTheDocument(); + + userEvent.click(screen.getByTestId('recurringCheck')); + + await waitFor(() => { + expect(screen.getByTestId('recurrenceOptions')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('recurrenceOptions')); + + await waitFor(() => { + expect(screen.getByTestId('dailyRecurrence')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('dailyRecurrence')); + + userEvent.click(screen.getByTestId('recurrenceOptions')); + + await waitFor(() => { + expect(screen.getByTestId('weeklyRecurrence')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('weeklyRecurrence')); + + userEvent.click(screen.getByTestId('recurrenceOptions')); + + await waitFor(() => { + expect( + screen.getByTestId('monthlyRecurrenceOnThatDay'), + ).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('monthlyRecurrenceOnThatDay')); + + userEvent.click(screen.getByTestId('recurrenceOptions')); + + await waitFor(() => { + expect( + screen.getByTestId('monthlyRecurrenceOnThatOccurence'), + ).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('monthlyRecurrenceOnThatOccurence')); + + userEvent.click(screen.getByTestId('recurrenceOptions')); + + await waitFor(() => { + expect( + screen.getByTestId('monthlyRecurrenceOnLastOccurence'), + ).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('monthlyRecurrenceOnLastOccurence')); + + // changing the startDate would change the weekDayOccurenceInMonth, if it is defined + fireEvent.change(startDatePicker, { + target: { value: formData.endDate }, + }); + + userEvent.click(screen.getByTestId('recurrenceOptions')); + + await waitFor(() => { + expect(screen.getByTestId('yearlyRecurrence')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('yearlyRecurrence')); + + userEvent.click(screen.getByTestId('recurrenceOptions')); + + await waitFor(() => { + expect( + screen.getByTestId('mondayToFridayRecurrence'), + ).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('mondayToFridayRecurrence')); + + await waitFor(() => { + expect(screen.getByTestId('recurrenceOptions')).toHaveTextContent( + 'Monday to Friday', + ); + }); + }, 30000); + + test('Creating a recurring event with the daily recurrence option', async () => { + render( + + + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createEventModalBtn')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('createEventModalBtn')); + + await waitFor(() => { + expect(screen.getByPlaceholderText(/Enter Title/i)).toBeInTheDocument(); + }); + + userEvent.type(screen.getByPlaceholderText(/Enter Title/i), formData.title); + + userEvent.type( + screen.getByPlaceholderText(/Enter Description/i), + formData.description, + ); + + userEvent.type( + screen.getByPlaceholderText(/Enter Location/i), + formData.location, + ); + + const startDatePicker = screen.getByLabelText('Start Date'); + const endDatePicker = screen.getByLabelText('End Date'); + + fireEvent.change(startDatePicker, { + target: { value: formData.startDate }, + }); + + fireEvent.change(endDatePicker, { + target: { value: formData.endDate }, + }); + + userEvent.click(screen.getByTestId('alldayCheck')); + + await waitFor(() => { + expect(screen.getByLabelText(translations.startTime)).toBeInTheDocument(); + }); + + const startTimePicker = screen.getByLabelText(translations.startTime); + const endTimePicker = screen.getByLabelText(translations.endTime); + + fireEvent.change(startTimePicker, { + target: { value: formData.startTime }, + }); + + fireEvent.change(endTimePicker, { + target: { value: formData.endTime }, + }); + + await waitFor(() => { + expect(screen.getByTestId('recurringCheck')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('recurringCheck')); + + await waitFor(() => { + expect(screen.getByTestId('recurrenceOptions')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('recurrenceOptions')); + + await waitFor(() => { + expect(screen.getByTestId('dailyRecurrence')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('dailyRecurrence')); + + expect(screen.getByPlaceholderText(/Enter Title/i)).toHaveValue( + formData.title, + ); + expect(screen.getByPlaceholderText(/Enter Location/i)).toHaveValue( + formData.location, + ); + expect(screen.getByPlaceholderText(/Enter Description/i)).toHaveValue( + formData.description, + ); + expect(startDatePicker).toHaveValue(formData.startDate); + expect(endDatePicker).toHaveValue(formData.endDate); + expect(startTimePicker).toHaveValue(formData.startTime); + expect(endTimePicker).toHaveValue(formData.endTime); + expect(screen.getByTestId('alldayCheck')).not.toBeChecked(); + expect(screen.getByTestId('recurringCheck')).toBeChecked(); + + expect(screen.getByTestId('recurrenceOptions')).toHaveTextContent('Daily'); + + userEvent.click(screen.getByTestId('createEventBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.eventCreated); + }); + + await waitFor(() => { + expect( + screen.queryByTestId('createEventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('Creating a recurring event with the monday to friday recurrence option', async () => { + render( + + + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createEventModalBtn')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('createEventModalBtn')); + + await waitFor(() => { + expect(screen.getByPlaceholderText(/Enter Title/i)).toBeInTheDocument(); + }); + + userEvent.type(screen.getByPlaceholderText(/Enter Title/i), formData.title); + + userEvent.type( + screen.getByPlaceholderText(/Enter Description/i), + formData.description, + ); + + userEvent.type( + screen.getByPlaceholderText(/Enter Location/i), + formData.location, + ); + + const startDatePicker = screen.getByLabelText('Start Date'); + const endDatePicker = screen.getByLabelText('End Date'); + + fireEvent.change(startDatePicker, { + target: { value: formData.startDate }, + }); + + fireEvent.change(endDatePicker, { + target: { value: formData.endDate }, + }); + + userEvent.click(screen.getByTestId('alldayCheck')); + + await waitFor(() => { + expect(screen.getByLabelText(translations.startTime)).toBeInTheDocument(); + }); + + const startTimePicker = screen.getByLabelText(translations.startTime); + const endTimePicker = screen.getByLabelText(translations.endTime); + + fireEvent.change(startTimePicker, { + target: { value: formData.startTime }, + }); + + fireEvent.change(endTimePicker, { + target: { value: formData.endTime }, + }); + + await waitFor(() => { + expect(screen.getByTestId('recurringCheck')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('recurringCheck')); + + await waitFor(() => { + expect(screen.getByTestId('recurrenceOptions')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('recurrenceOptions')); + + await waitFor(() => { + expect( + screen.getByTestId('mondayToFridayRecurrence'), + ).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('mondayToFridayRecurrence')); + + expect(screen.getByPlaceholderText(/Enter Title/i)).toHaveValue( + formData.title, + ); + expect(screen.getByPlaceholderText(/Enter Location/i)).toHaveValue( + formData.location, + ); + expect(screen.getByPlaceholderText(/Enter Description/i)).toHaveValue( + formData.description, + ); + expect(startDatePicker).toHaveValue(formData.startDate); + expect(endDatePicker).toHaveValue(formData.endDate); + expect(startTimePicker).toHaveValue(formData.startTime); + expect(endTimePicker).toHaveValue(formData.endTime); + expect(screen.getByTestId('alldayCheck')).not.toBeChecked(); + expect(screen.getByTestId('recurringCheck')).toBeChecked(); + + expect(screen.getByTestId('recurrenceOptions')).toHaveTextContent( + 'Monday to Friday', + ); + + userEvent.click(screen.getByTestId('createEventBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.eventCreated); + }); + + await waitFor(() => { + expect( + screen.queryByTestId('createEventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); +}); diff --git a/src/components/RecurrenceOptions/RecurrenceOptions.tsx b/src/components/RecurrenceOptions/RecurrenceOptions.tsx new file mode 100644 index 0000000000..f3a4e61226 --- /dev/null +++ b/src/components/RecurrenceOptions/RecurrenceOptions.tsx @@ -0,0 +1,231 @@ +import React, { useState } from 'react'; +import { Dropdown, OverlayTrigger } from 'react-bootstrap'; +import { + Days, + Frequency, + type InterfaceRecurrenceRuleState, + getRecurrenceRuleText, + getWeekDayOccurenceInMonth, + isLastOccurenceOfWeekDay, + mondayToFriday, +} from 'utils/recurrenceUtils'; +import CustomRecurrenceModal from './CustomRecurrenceModal'; + +interface InterfaceRecurrenceOptionsProps { + recurrenceRuleState: InterfaceRecurrenceRuleState; + recurrenceRuleText: string; + setRecurrenceRuleState: ( + state: React.SetStateAction, + ) => void; + popover: JSX.Element; + t: (key: string) => string; + tCommon: (key: string) => string; +} + +const RecurrenceOptions: React.FC = ({ + recurrenceRuleState, + recurrenceRuleText, + setRecurrenceRuleState, + popover, + t, + tCommon, +}) => { + const [customRecurrenceModalIsOpen, setCustomRecurrenceModalIsOpen] = + useState(false); + + const { recurrenceStartDate } = recurrenceRuleState; + + const hideCustomRecurrenceModal = (): void => { + setCustomRecurrenceModalIsOpen(false); + }; + + return ( + <> + + + {recurrenceRuleText.length > 45 ? ( + + + {`${recurrenceRuleText.substring(0, 45)}...`} + + + ) : ( + {recurrenceRuleText} + )} + + + + + setRecurrenceRuleState({ + ...recurrenceRuleState, + frequency: Frequency.DAILY, + weekDayOccurenceInMonth: undefined, + }) + } + data-testid="dailyRecurrence" + > + + {getRecurrenceRuleText({ + ...recurrenceRuleState, + frequency: Frequency.DAILY, + })} + + + + setRecurrenceRuleState({ + ...recurrenceRuleState, + frequency: Frequency.WEEKLY, + weekDays: [Days[recurrenceStartDate.getDay()]], + weekDayOccurenceInMonth: undefined, + }) + } + data-testid="weeklyRecurrence" + > + + {getRecurrenceRuleText({ + ...recurrenceRuleState, + frequency: Frequency.WEEKLY, + weekDays: [Days[recurrenceStartDate.getDay()]], + })} + + + + setRecurrenceRuleState({ + ...recurrenceRuleState, + frequency: Frequency.MONTHLY, + weekDayOccurenceInMonth: undefined, + }) + } + data-testid="monthlyRecurrenceOnThatDay" + > + + {getRecurrenceRuleText({ + ...recurrenceRuleState, + frequency: Frequency.MONTHLY, + weekDayOccurenceInMonth: undefined, + })} + + + {getWeekDayOccurenceInMonth(recurrenceStartDate) !== 5 && ( + + setRecurrenceRuleState({ + ...recurrenceRuleState, + frequency: Frequency.MONTHLY, + weekDays: [Days[recurrenceStartDate.getDay()]], + weekDayOccurenceInMonth: + getWeekDayOccurenceInMonth(recurrenceStartDate), + }) + } + data-testid="monthlyRecurrenceOnThatOccurence" + > + + {getRecurrenceRuleText({ + ...recurrenceRuleState, + frequency: Frequency.MONTHLY, + weekDays: [Days[recurrenceStartDate.getDay()]], + weekDayOccurenceInMonth: + getWeekDayOccurenceInMonth(recurrenceStartDate), + })} + + + )} + {isLastOccurenceOfWeekDay(recurrenceStartDate) && ( + + setRecurrenceRuleState({ + ...recurrenceRuleState, + frequency: Frequency.MONTHLY, + weekDays: [Days[recurrenceStartDate.getDay()]], + weekDayOccurenceInMonth: -1, + }) + } + data-testid="monthlyRecurrenceOnLastOccurence" + > + + {getRecurrenceRuleText({ + ...recurrenceRuleState, + frequency: Frequency.MONTHLY, + weekDays: [Days[recurrenceStartDate.getDay()]], + weekDayOccurenceInMonth: -1, + })} + + + )} + + setRecurrenceRuleState({ + ...recurrenceRuleState, + frequency: Frequency.YEARLY, + weekDayOccurenceInMonth: undefined, + }) + } + data-testid="yearlyRecurrence" + > + + {getRecurrenceRuleText({ + ...recurrenceRuleState, + frequency: Frequency.YEARLY, + weekDayOccurenceInMonth: undefined, + })} + + + + setRecurrenceRuleState({ + ...recurrenceRuleState, + frequency: Frequency.WEEKLY, + weekDays: mondayToFriday, + weekDayOccurenceInMonth: undefined, + }) + } + data-testid="mondayToFridayRecurrence" + > + + {getRecurrenceRuleText({ + ...recurrenceRuleState, + frequency: Frequency.WEEKLY, + weekDays: mondayToFriday, + })} + + + setCustomRecurrenceModalIsOpen(true)} + data-testid="customRecurrence" + > + Custom... + + + + + {/* Custom Recurrence Modal */} + + + ); +}; + +export default RecurrenceOptions; diff --git a/src/components/RequestsTableItem/RequestsTableItem.module.css b/src/components/RequestsTableItem/RequestsTableItem.module.css new file mode 100644 index 0000000000..9f12bfe996 --- /dev/null +++ b/src/components/RequestsTableItem/RequestsTableItem.module.css @@ -0,0 +1,66 @@ +.tableItem { + width: 100%; +} + +.tableItem td { + padding: 0.5rem; +} + +.tableItem .index { + padding-left: 2.5rem; + padding-top: 1rem; +} + +.tableItem .name { + padding-left: 1.5rem; + padding-top: 1rem; +} + +.tableItem .email { + padding-left: 1.5rem; + padding-top: 1rem; +} + +.acceptButton { + background: #31bb6b; + width: 120px; + height: 46px; + margin-left: -1rem; +} + +.rejectButton { + background: #dc3545; + width: 120px; + height: 46px; + margin-left: -1rem; +} + +@media (max-width: 1020px) { + .tableItem .index { + padding-left: 2rem; + } + + .tableItem .name, + .tableItem .email { + padding-left: 1rem; + } + + .acceptButton, + .rejectButton { + margin-left: -0.25rem; + } +} + +@media (max-width: 520px) { + .tableItem .index, + .tableItem .name, + .tableItem .email { + padding-left: 1rem; + } + + .acceptButton, + .rejectButton { + margin-left: 0; + width: 100%; + } +} diff --git a/src/components/RequestsTableItem/RequestsTableItem.test.tsx b/src/components/RequestsTableItem/RequestsTableItem.test.tsx new file mode 100644 index 0000000000..866abc7f68 --- /dev/null +++ b/src/components/RequestsTableItem/RequestsTableItem.test.tsx @@ -0,0 +1,147 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { act, render, screen } from '@testing-library/react'; +import { I18nextProvider } from 'react-i18next'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18nForTest from 'utils/i18nForTest'; +import type { InterfaceRequestsListItem } from './RequestsTableItem'; +import { MOCKS } from './RequestsTableItemMocks'; +import RequestsTableItem from './RequestsTableItem'; +import { BrowserRouter } from 'react-router-dom'; +const link = new StaticMockLink(MOCKS, true); +import useLocalStorage from 'utils/useLocalstorage'; +import userEvent from '@testing-library/user-event'; + +const { setItem } = useLocalStorage(); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} +const resetAndRefetchMock = jest.fn(); + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + warning: jest.fn(), + }, +})); + +beforeEach(() => { + setItem('id', '123'); +}); + +afterEach(() => { + localStorage.clear(); + jest.clearAllMocks(); +}); + +describe('Testing User Table Item', () => { + console.error = jest.fn((message) => { + if (message.includes('validateDOMNesting')) { + return; + } + console.warn(message); + }); + test('Should render props and text elements test for the page component', async () => { + const props: { + request: InterfaceRequestsListItem; + index: number; + resetAndRefetch: () => void; + } = { + request: { + _id: '123', + user: { + firstName: 'John', + lastName: 'Doe', + email: 'john@example.com', + }, + }, + index: 1, + resetAndRefetch: resetAndRefetchMock, + }; + + render( + + + + + + + , + ); + + await wait(); + expect(screen.getByText(/2./i)).toBeInTheDocument(); + expect(screen.getByText(/John Doe/i)).toBeInTheDocument(); + expect(screen.getByText(/john@example.com/i)).toBeInTheDocument(); + }); + + test('Accept MembershipRequest Button works properly', async () => { + const props: { + request: InterfaceRequestsListItem; + index: number; + resetAndRefetch: () => void; + } = { + request: { + _id: '123', + user: { + firstName: 'John', + lastName: 'Doe', + email: 'john@example.com', + }, + }, + index: 1, + resetAndRefetch: resetAndRefetchMock, + }; + + render( + + + + + + + , + ); + + await wait(); + userEvent.click(screen.getByTestId('acceptMembershipRequestBtn123')); + }); + + test('Reject MembershipRequest Button works properly', async () => { + const props: { + request: InterfaceRequestsListItem; + index: number; + resetAndRefetch: () => void; + } = { + request: { + _id: '123', + user: { + firstName: 'John', + lastName: 'Doe', + email: 'john@example.com', + }, + }, + index: 1, + resetAndRefetch: resetAndRefetchMock, + }; + + render( + + + + + + + , + ); + + await wait(); + userEvent.click(screen.getByTestId('rejectMembershipRequestBtn123')); + }); +}); diff --git a/src/components/RequestsTableItem/RequestsTableItem.tsx b/src/components/RequestsTableItem/RequestsTableItem.tsx new file mode 100644 index 0000000000..9c4c042324 --- /dev/null +++ b/src/components/RequestsTableItem/RequestsTableItem.tsx @@ -0,0 +1,109 @@ +import { useMutation } from '@apollo/client'; +import { + ACCEPT_ORGANIZATION_REQUEST_MUTATION, + REJECT_ORGANIZATION_REQUEST_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import React from 'react'; +import { Button } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; +import { errorHandler } from 'utils/errorHandler'; +import styles from './RequestsTableItem.module.css'; + +export interface InterfaceRequestsListItem { + _id: string; + user: { + firstName: string; + lastName: string; + email: string; + }; +} + +type Props = { + request: InterfaceRequestsListItem; + index: number; + resetAndRefetch: () => void; +}; + +const RequestsTableItem = (props: Props): JSX.Element => { + const { t } = useTranslation('translation', { keyPrefix: 'requests' }); + const { request, index, resetAndRefetch } = props; + const [acceptUser] = useMutation(ACCEPT_ORGANIZATION_REQUEST_MUTATION); + const [rejectUser] = useMutation(REJECT_ORGANIZATION_REQUEST_MUTATION); + + const handleAcceptUser = async ( + membershipRequestId: string, + ): Promise => { + try { + const { data } = await acceptUser({ + variables: { + id: membershipRequestId, + }, + }); + /* istanbul ignore next */ + if (data) { + toast.success(t('acceptedSuccessfully')); + resetAndRefetch(); + } + } catch (error: any) { + /* istanbul ignore next */ + errorHandler(t, error); + } + }; + + const handleRejectUser = async ( + membershipRequestId: string, + ): Promise => { + try { + const { data } = await rejectUser({ + variables: { + id: membershipRequestId, + }, + }); + /* istanbul ignore next */ + if (data) { + toast.success(t('rejectedSuccessfully')); + resetAndRefetch(); + } + } catch (error: any) { + /* istanbul ignore next */ + errorHandler(t, error); + } + }; + + return ( + + {index + 1}. + {`${request.user.firstName} ${request.user.lastName}`} + {request.user.email} + + + + + + + + ); +}; + +export default RequestsTableItem; diff --git a/src/components/RequestsTableItem/RequestsTableItemMocks.ts b/src/components/RequestsTableItem/RequestsTableItemMocks.ts new file mode 100644 index 0000000000..22ea245d3a --- /dev/null +++ b/src/components/RequestsTableItem/RequestsTableItemMocks.ts @@ -0,0 +1,37 @@ +import { + ACCEPT_ORGANIZATION_REQUEST_MUTATION, + REJECT_ORGANIZATION_REQUEST_MUTATION, +} from 'GraphQl/Mutations/mutations'; + +export const MOCKS = [ + { + request: { + query: ACCEPT_ORGANIZATION_REQUEST_MUTATION, + variables: { + id: '1', + }, + }, + result: { + data: { + acceptMembershipRequest: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: REJECT_ORGANIZATION_REQUEST_MUTATION, + variables: { + id: '1', + }, + }, + result: { + data: { + rejectMembershipRequest: { + _id: '1', + }, + }, + }, + }, +]; diff --git a/src/components/SecuredRoute/SecuredRoute.tsx b/src/components/SecuredRoute/SecuredRoute.tsx new file mode 100644 index 0000000000..4bf361eb77 --- /dev/null +++ b/src/components/SecuredRoute/SecuredRoute.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { Navigate, Outlet } from 'react-router-dom'; +import { toast } from 'react-toastify'; +import PageNotFound from 'screens/PageNotFound/PageNotFound'; +import useLocalStorage from 'utils/useLocalstorage'; +const { getItem, setItem } = useLocalStorage(); + +const SecuredRoute = (): JSX.Element => { + const isLoggedIn = getItem('IsLoggedIn'); + const adminFor = getItem('AdminFor'); + return isLoggedIn === 'TRUE' ? ( + <>{adminFor != null ? : } + ) : ( + + ); +}; + +const timeoutMinutes = 15; +const timeoutMilliseconds = timeoutMinutes * 60 * 1000; + +const inactiveIntervalMin = 1; +const inactiveIntervalMilsec = inactiveIntervalMin * 60 * 1000; +let lastActive: number = Date.now(); + +document.addEventListener('mousemove', () => { + lastActive = Date.now(); +}); + +setInterval(() => { + const currentTime = Date.now(); + const timeSinceLastActive = currentTime - lastActive; + + if (timeSinceLastActive > timeoutMilliseconds) { + toast.warn('Kindly relogin as sessison has expired'); + + window.location.href = '/'; + setItem('IsLoggedIn', 'FALSE'); + } +}, inactiveIntervalMilsec); + +export default SecuredRoute; diff --git a/src/components/SuperAdminScreen/SuperAdminScreen.module.css b/src/components/SuperAdminScreen/SuperAdminScreen.module.css new file mode 100644 index 0000000000..9496ef95fa --- /dev/null +++ b/src/components/SuperAdminScreen/SuperAdminScreen.module.css @@ -0,0 +1,101 @@ +.pageContainer { + display: flex; + flex-direction: column; + min-height: 100vh; + padding: 1rem 1.5rem 0 calc(300px + 2rem + 1.5rem); +} + +.expand { + padding-left: 4rem; + animation: moveLeft 0.5s ease-in-out; +} + +.contract { + padding-left: calc(300px + 2rem + 1.5rem); + animation: moveRight 0.5s ease-in-out; +} + +.collapseSidebarButton { + position: fixed; + height: 40px; + bottom: 0; + z-index: 9999; + width: calc(300px + 2rem); + background-color: rgba(245, 245, 245, 0.7); + color: black; + border: none; + border-radius: 0px; +} + +.collapseSidebarButton:hover, +.opendrawer:hover { + opacity: 1; + color: black !important; +} +.opendrawer { + position: fixed; + display: flex; + align-items: center; + justify-content: center; + top: 0; + left: 0; + width: 40px; + height: 100vh; + z-index: 9999; + background-color: rgba(245, 245, 245); + border: none; + border-radius: 0px; + margin-right: 20px; + color: black; +} + +@media (max-width: 1120px) { + .contract { + padding-left: calc(250px + 2rem + 1.5rem); + } + .collapseSidebarButton { + width: calc(250px + 2rem); + } +} + +/* For tablets */ +@media (max-width: 820px) { + .pageContainer { + padding-left: 2.5rem; + } + + .opendrawer { + width: 25px; + } + + .contract, + .expand { + animation: none; + } + + .collapseSidebarButton { + width: 100%; + left: 0; + right: 0; + } +} + +@keyframes moveLeft { + from { + padding-left: calc(300px + 2rem + 1.5rem); + } + + to { + padding-left: 1.5rem; + } +} + +@keyframes moveRight { + from { + padding-left: 1.5rem; + } + + to { + padding-left: calc(300px + 2rem + 1.5rem); + } +} diff --git a/src/components/SuperAdminScreen/SuperAdminScreen.test.tsx b/src/components/SuperAdminScreen/SuperAdminScreen.test.tsx new file mode 100644 index 0000000000..84b740ab12 --- /dev/null +++ b/src/components/SuperAdminScreen/SuperAdminScreen.test.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +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 { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; +import SuperAdminScreen from './SuperAdminScreen'; + +const resizeWindow = (width: number): void => { + window.innerWidth = width; + fireEvent(window, new Event('resize')); +}; + +const clickToggleMenuBtn = (toggleButton: HTMLElement): void => { + fireEvent.click(toggleButton); +}; + +describe('Testing LeftDrawer in SuperAdminScreen', () => { + test('Testing LeftDrawer in page functionality', async () => { + render( + + + + + + + + + , + ); + + const toggleButton = screen.getByTestId('closeMenu') as HTMLElement; + const icon = toggleButton.querySelector('i'); + + // Resize window to a smaller width + resizeWindow(800); + clickToggleMenuBtn(toggleButton); + expect(icon).toHaveClass('fa fa-angle-double-left'); + + // Resize window back to a larger width + resizeWindow(1000); + clickToggleMenuBtn(toggleButton); + expect(icon).toHaveClass('fa fa-angle-double-right'); + + clickToggleMenuBtn(toggleButton); + expect(icon).toHaveClass('fa fa-angle-double-left'); + }); +}); diff --git a/src/components/SuperAdminScreen/SuperAdminScreen.tsx b/src/components/SuperAdminScreen/SuperAdminScreen.tsx new file mode 100644 index 0000000000..f7191289eb --- /dev/null +++ b/src/components/SuperAdminScreen/SuperAdminScreen.tsx @@ -0,0 +1,86 @@ +import LeftDrawer from 'components/LeftDrawer/LeftDrawer'; +import React, { useEffect, useState } from 'react'; +import Button from 'react-bootstrap/Button'; +import { useTranslation } from 'react-i18next'; +import { Outlet, useLocation } from 'react-router-dom'; +import styles from './SuperAdminScreen.module.css'; +import ProfileDropdown from 'components/ProfileDropdown/ProfileDropdown'; + +const superAdminScreen = (): JSX.Element => { + const location = useLocation(); + const titleKey = map[location.pathname.split('/')[1]]; + const { t } = useTranslation('translation', { keyPrefix: titleKey }); + const [hideDrawer, setHideDrawer] = useState(null); + + const handleResize = (): void => { + if (window.innerWidth <= 820) { + setHideDrawer(!hideDrawer); + } + }; + + useEffect(() => { + handleResize(); + window.addEventListener('resize', handleResize); + return () => { + window.removeEventListener('resize', handleResize); + }; + }, []); + + return ( + <> + {hideDrawer ? ( + + ) : ( + + )} + +
    +
    +
    +

    {t('title')}

    +
    + +
    + +
    + + ); +}; + +export default superAdminScreen; + +const map: Record< + string, + 'orgList' | 'requests' | 'users' | 'memberDetail' | 'communityProfile' +> = { + orglist: 'orgList', + requests: 'requests', + users: 'users', + member: 'memberDetail', + communityProfile: 'communityProfile', +}; diff --git a/src/components/TableLoader/TableLoader.module.css b/src/components/TableLoader/TableLoader.module.css new file mode 100644 index 0000000000..66349e2aa9 --- /dev/null +++ b/src/components/TableLoader/TableLoader.module.css @@ -0,0 +1,3 @@ +.loadingItem { + height: 30px; +} diff --git a/src/components/TableLoader/TableLoader.test.tsx b/src/components/TableLoader/TableLoader.test.tsx new file mode 100644 index 0000000000..e8400c84ef --- /dev/null +++ b/src/components/TableLoader/TableLoader.test.tsx @@ -0,0 +1,78 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { BrowserRouter } from 'react-router-dom'; + +import type { InterfaceTableLoader } from './TableLoader'; +import TableLoader from './TableLoader'; + +beforeAll(() => { + console.error = jest.fn(); +}); + +describe('Testing Loader component', () => { + test('Component should be rendered properly only headerTitles is provided', () => { + const props: InterfaceTableLoader = { + noOfRows: 10, + headerTitles: ['header1', 'header2', 'header3'], + }; + render( + + + , + ); + // Check if header titles are rendered properly + const data = props.headerTitles as string[]; + data.forEach((title) => { + expect(screen.getByText(title)).toBeInTheDocument(); + }); + + // Check if elements are rendered properly + for (let rowIndex = 0; rowIndex < props.noOfRows; rowIndex++) { + expect( + screen.getByTestId(`row-${rowIndex}-tableLoading`), + ).toBeInTheDocument(); + for (let colIndex = 0; colIndex < data.length; colIndex++) { + expect( + screen.getByTestId(`row-${rowIndex}-col-${colIndex}-tableLoading`), + ).toBeInTheDocument(); + } + } + }); + test('Component should be rendered properly only noCols is provided', () => { + const props: InterfaceTableLoader = { + noOfRows: 10, + noOfCols: 3, + }; + render( + + + , + ); + // Check if header titles are rendered properly + const data = [...Array(props.noOfCols)]; + + // Check if elements are rendered properly + for (let rowIndex = 0; rowIndex < props.noOfRows; rowIndex++) { + expect( + screen.getByTestId(`row-${rowIndex}-tableLoading`), + ).toBeInTheDocument(); + for (let colIndex = 0; colIndex < data.length; colIndex++) { + expect( + screen.getByTestId(`row-${rowIndex}-col-${colIndex}-tableLoading`), + ).toBeInTheDocument(); + } + } + }); + test('Component should be throw error when noOfCols and headerTitles are undefined', () => { + const props = { + noOfRows: 10, + }; + expect(() => { + render( + + + , + ); + }).toThrowError(); + }); +}); diff --git a/src/components/TableLoader/TableLoader.tsx b/src/components/TableLoader/TableLoader.tsx new file mode 100644 index 0000000000..6d99d6fe3f --- /dev/null +++ b/src/components/TableLoader/TableLoader.tsx @@ -0,0 +1,67 @@ +import React, { useEffect } from 'react'; +import styles from './TableLoader.module.css'; +import { Table } from 'react-bootstrap'; + +export interface InterfaceTableLoader { + noOfRows: number; + headerTitles?: string[]; + noOfCols?: number; +} + +const tableLoader = (props: InterfaceTableLoader): JSX.Element => { + const { noOfRows, headerTitles, noOfCols } = props; + + useEffect(() => { + if (headerTitles == undefined && noOfCols == undefined) { + throw new Error( + 'TableLoader error Either headerTitles or noOfCols is required !', + ); + } + }, []); + + return ( + <> + + + + {headerTitles + ? headerTitles.map((title, index) => { + return ; + }) + : noOfCols && + [...Array(noOfCols)].map((_, index) => { + return + + + + {[...Array(noOfRows)].map((_, rowIndex) => { + return ( + + {[...Array(headerTitles ? headerTitles?.length : noOfCols)].map( + (_, colIndex) => { + return ( + + ); + }, + )} + + ); + })} + +
    {title}; + })} +
    +
    +
    + + ); +}; + +export default tableLoader; diff --git a/src/components/UserListCard/UserListCard.module.css b/src/components/UserListCard/UserListCard.module.css new file mode 100644 index 0000000000..187757a531 --- /dev/null +++ b/src/components/UserListCard/UserListCard.module.css @@ -0,0 +1,74 @@ +.memberlist { + margin-top: -1px; +} +.memberimg { + width: 200px; + height: 100px; + border-radius: 7px; + margin-left: 20px; +} +.singledetails { + display: flex; + flex-direction: row; + justify-content: space-between; +} +.singledetails p { + margin-bottom: -5px; +} +.singledetails_data_left { + margin-top: 10px; + margin-left: 10px; + color: #707070; +} +.singledetails_data_right { + justify-content: right; + margin-top: 10px; + text-align: right; + color: #707070; +} +.membername { + font-size: 16px; + font-weight: bold; +} +.memberfont { + margin-top: 3px; +} +.memberfont > span { + width: 80%; +} +.memberfontcreated { + margin-top: 18px; +} +.memberfontcreatedbtn { + margin-top: 33px; + border-radius: 7px; + border-color: #31bb6b; + background-color: #31bb6b; + color: white; + padding-right: 10px; + padding-left: 10px; + justify-content: flex-end; + float: right; + text-align: right; + box-shadow: none; +} +#grid_wrapper { + align-items: left; +} +.peoplelistdiv { + margin-right: 50px; +} +@media only screen and (max-width: 600px) { + .singledetails { + margin-left: 20px; + } + .memberimg { + margin: auto; + } + .singledetails_data_right { + margin-right: -52px; + } + .singledetails_data_left { + margin-left: 0px; + } +} diff --git a/src/components/UserListCard/UserListCard.test.tsx b/src/components/UserListCard/UserListCard.test.tsx new file mode 100644 index 0000000000..9f59bb92ce --- /dev/null +++ b/src/components/UserListCard/UserListCard.test.tsx @@ -0,0 +1,82 @@ +import React from 'react'; +import { act, render, screen } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import userEvent from '@testing-library/user-event'; +import { I18nextProvider } from 'react-i18next'; + +import UserListCard from './UserListCard'; +import { ADD_ADMIN_MUTATION } from 'GraphQl/Mutations/mutations'; +import i18nForTest from 'utils/i18nForTest'; +import { BrowserRouter } from 'react-router-dom'; +import { StaticMockLink } from 'utils/StaticMockLink'; + +const MOCKS = [ + { + request: { + query: ADD_ADMIN_MUTATION, + variable: { userid: '784', orgid: '554' }, + }, + result: { + data: { + organizations: [ + { + _id: '1', + }, + ], + }, + }, + }, +]; +const link = new StaticMockLink(MOCKS, true); +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +describe('Testing User List Card', () => { + global.alert = jest.fn(); + + test('Should render props and text elements test for the page component', async () => { + const props = { + key: 123, + id: '456', + }; + + render( + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByText(/Add Admin/i)); + }); + + test('Should render text elements when props value is not passed', async () => { + const props = { + key: 123, + id: '456', + }; + + render( + + + + + + + , + ); + + await wait(); + userEvent.click(screen.getByText(/Add Admin/i)); + }); +}); diff --git a/src/components/UserListCard/UserListCard.tsx b/src/components/UserListCard/UserListCard.tsx new file mode 100644 index 0000000000..5954e22e6c --- /dev/null +++ b/src/components/UserListCard/UserListCard.tsx @@ -0,0 +1,56 @@ +import React from 'react'; +import Button from 'react-bootstrap/Button'; +import { useMutation } from '@apollo/client'; +import { toast } from 'react-toastify'; +import { useTranslation } from 'react-i18next'; + +import { ADD_ADMIN_MUTATION } from 'GraphQl/Mutations/mutations'; +import styles from './UserListCard.module.css'; +import { useParams } from 'react-router-dom'; +import { errorHandler } from 'utils/errorHandler'; + +interface InterfaceUserListCardProps { + key: number; + id: string; +} + +function userListCard(props: InterfaceUserListCardProps): JSX.Element { + const { orgId: currentUrl } = useParams(); + const [adda] = useMutation(ADD_ADMIN_MUTATION); + + const { t } = useTranslation('translation', { + keyPrefix: 'userListCard', + }); + + const addAdmin = async (): Promise => { + try { + const { data } = await adda({ + variables: { + userid: props.id, + orgid: currentUrl, + }, + }); + + /* istanbul ignore next */ + if (data) { + toast.success(t('addedAsAdmin')); + setTimeout(() => { + window.location.reload(); + }, 2000); + } + } catch (error: any) { + /* istanbul ignore next */ + errorHandler(t, error); + } + }; + + return ( + <> + + + ); +} +export {}; +export default userListCard; diff --git a/src/components/UserPasswordUpdate/UserPasswordUpdate.module.css b/src/components/UserPasswordUpdate/UserPasswordUpdate.module.css new file mode 100644 index 0000000000..90b5c09be3 --- /dev/null +++ b/src/components/UserPasswordUpdate/UserPasswordUpdate.module.css @@ -0,0 +1,97 @@ +/* .userupdatediv{ + border: 1px solid #e8e5e5; + box-shadow: 2px 1px #e8e5e5; + padding:25px 16px; + border-radius: 5px; + background:#fdfdfd; +} */ +.settingstitle { + color: #707070; + font-size: 20px; + margin-bottom: 30px; + text-align: center; + margin-top: -10px; +} +.dispflex { + display: flex; + justify-content: flex-start; + margin: 0 auto; +} +.dispbtnflex { + width: 90%; + margin-top: 20px; + display: flex; + margin: 0 30%; +} +.dispflex > div { + width: 50%; + margin-right: 50px; +} + +.radio_buttons > input { + margin-bottom: 20px; + border: none; + box-shadow: none; + padding: 0 0; + border-radius: 5px; + background: none; + width: 50%; +} + +.whitebtn { + margin: 1rem 0 0; + margin-top: 10px; + border: 1px solid #e8e5e5; + box-shadow: 0 2px 2px #e8e5e5; + padding: 10px 20px; + border-radius: 5px; + background: none; + width: 20%; + font-size: 16px; + color: #31bb6b; + outline: none; + font-weight: 600; + cursor: pointer; + float: left; + transition: + transform 0.2s, + box-shadow 0.2s; +} +.greenregbtn { + margin: 1rem 0 0; + margin-top: 10px; + margin-right: 30px; + border: 1px solid #e8e5e5; + box-shadow: 0 2px 2px #e8e5e5; + padding: 10px 10px; + border-radius: 5px; + background-color: #31bb6b; + width: 20%; + font-size: 16px; + color: white; + outline: none; + font-weight: 600; + cursor: pointer; + transition: + transform 0.2s, + box-shadow 0.2s; +} +.radio_buttons { + width: 55%; + margin-top: 10px; + display: flex; + color: #707070; + font-weight: 600; + font-size: 14px; +} +.radio_buttons > input { + transform: scale(1.2); +} +.radio_buttons > label { + margin-top: -4px; + margin-left: 0px; + margin-right: 7px; +} +.idtitle { + width: 88%; +} diff --git a/src/components/UserPasswordUpdate/UserPasswordUpdate.test.tsx b/src/components/UserPasswordUpdate/UserPasswordUpdate.test.tsx new file mode 100644 index 0000000000..4fcbb18070 --- /dev/null +++ b/src/components/UserPasswordUpdate/UserPasswordUpdate.test.tsx @@ -0,0 +1,148 @@ +import React from 'react'; +import { act, render, screen } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import userEvent from '@testing-library/user-event'; +import { I18nextProvider } from 'react-i18next'; +import { 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'; + +jest.mock('react-toastify', () => ({ + toast: { + error: jest.fn(), + success: jest.fn(), + }, +})); + +const MOCKS = [ + { + request: { + query: UPDATE_USER_PASSWORD_MUTATION, + variable: { + previousPassword: 'anshgoyal', + newPassword: 'anshgoyalansh', + confirmNewPassword: 'anshgoyalansh', + }, + }, + result: { + data: { + users: [ + { + _id: '1', + }, + ], + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); + +async function wait(ms = 5): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +describe('Testing User Password Update', () => { + const props = { + key: '123', + id: '1', + }; + + const formData = { + previousPassword: 'Palisadoes', + newPassword: 'ThePalisadoesFoundation', + wrongPassword: 'This is wrong passoword', + confirmNewPassword: 'ThePalisadoesFoundation', + }; + + global.alert = jest.fn(); + + test('should render props and text elements test for the page component', 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(screen.getByText(/Cancel/i)).toBeTruthy(); + expect( + screen.getByPlaceholderText(/Previous Password/i), + ).toBeInTheDocument(); + expect( + screen.getByPlaceholderText(/Confirm New Password/i), + ).toBeInTheDocument(); + }); + + test('displays an error when the password field is empty', async () => { + render( + + + + + , + ); + + userEvent.click(screen.getByText(/Save Changes/i)); + + await wait(); + expect(mockToast.error).toHaveBeenCalledWith(`Password can't be empty`); + }); + + test('displays an error when new and confirm password field does not match', async () => { + render( + + + + + , + ); + + await wait(); + + userEvent.type( + screen.getByPlaceholderText(/Previous Password/i), + formData.previousPassword, + ); + userEvent.type( + screen.getAllByPlaceholderText(/New Password/i)[0], + formData.wrongPassword, + ); + userEvent.type( + screen.getByPlaceholderText(/Confirm New Password/i), + formData.confirmNewPassword, + ); + + userEvent.click(screen.getByText(/Save Changes/i)); + + expect(screen.getByText(/Cancel/i)).toBeTruthy(); + await wait(); + expect(mockToast.error).toHaveBeenCalledWith( + 'New and Confirm password do not match.', + ); + }); +}); diff --git a/src/components/UserPasswordUpdate/UserPasswordUpdate.tsx b/src/components/UserPasswordUpdate/UserPasswordUpdate.tsx new file mode 100644 index 0000000000..f9cb899f2d --- /dev/null +++ b/src/components/UserPasswordUpdate/UserPasswordUpdate.tsx @@ -0,0 +1,157 @@ +import React from 'react'; +import { useMutation } from '@apollo/client'; +import { UPDATE_USER_PASSWORD_MUTATION } from 'GraphQl/Mutations/mutations'; +import { useTranslation } from 'react-i18next'; +import Button from 'react-bootstrap/Button'; +import styles from './UserPasswordUpdate.module.css'; +import { toast } from 'react-toastify'; +import { Form } from 'react-bootstrap'; + +interface InterfaceUserPasswordUpdateProps { + id: string; +} + +const UserUpdate: React.FC< + InterfaceUserPasswordUpdateProps +> = (): JSX.Element => { + const { t } = useTranslation('translation', { + keyPrefix: 'userPasswordUpdate', + }); + const { t: tCommon } = useTranslation('common'); + const [formState, setFormState] = React.useState({ + previousPassword: '', + newPassword: '', + confirmNewPassword: '', + }); + + const [login] = useMutation(UPDATE_USER_PASSWORD_MUTATION); + + const loginLink = async (): Promise => { + if ( + !formState.previousPassword || + !formState.newPassword || + !formState.confirmNewPassword + ) { + toast.error(t('passCantBeEmpty')); + return; + } + + if (formState.newPassword !== formState.confirmNewPassword) { + toast.error(t('passNoMatch')); + return; + } + + try { + const { data } = await login({ + variables: { + previousPassword: formState.previousPassword, + newPassword: formState.newPassword, + confirmNewPassword: formState.confirmNewPassword, + }, + }); + /* istanbul ignore next */ + if (data) { + toast.success(tCommon('updatedSuccessfully', { item: 'Password' })); + setTimeout(() => { + window.location.reload(); + }, 2000); + } + } catch (error: unknown) { + /* istanbul ignore next */ + if (error instanceof Error) { + toast.error(error.toString()); + } + } + }; + + /* istanbul ignore next */ + const cancelUpdate = (): void => { + window.location.reload(); + }; + + return ( + <> +
    +
    + {/*

    Update Your Details

    */} +
    +
    + + { + setFormState({ + ...formState, + previousPassword: e.target.value, + }); + }} + /> +
    +
    +
    +
    + + { + setFormState({ + ...formState, + newPassword: e.target.value, + }); + }} + /> +
    +
    +
    +
    + + { + setFormState({ + ...formState, + confirmNewPassword: e.target.value, + }); + }} + /> +
    +
    +
    + + +
    +
    +
    + + ); +}; +export default UserUpdate; diff --git a/src/components/UserPortal/ChatRoom/ChatRoom.module.css b/src/components/UserPortal/ChatRoom/ChatRoom.module.css new file mode 100644 index 0000000000..f6aa3e374b --- /dev/null +++ b/src/components/UserPortal/ChatRoom/ChatRoom.module.css @@ -0,0 +1,110 @@ +.chatAreaContainer { + padding: 10px; + flex-grow: 1; + /* background-color: rgba(196, 255, 211, 0.3); */ +} + +.backgroundWhite { + background-color: white; +} + +.grey { + color: grey; +} + +.header { + position: sticky; + top: 0px; + background: white; +} + +.userInfo { + display: flex; + border-bottom: 1px solid black; + padding-bottom: 5px; + align-items: center; + margin-top: 5px; +} + +.contactImage { + width: 45px !important; + height: auto !important; + border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; +} + +.messageSentContainer { + display: flex; + justify-content: flex-end; +} + +.messageReceivedContainer { + display: flex; + align-items: flex-end; +} + +.messageReceived { + border: 1px solid #c2c2c2; + border-radius: 8px 8px 8px 0px; + padding: 4px 6px; + margin: 4px 6px; + width: fit-content; + max-width: 75%; + min-width: 80px; +} + +.messageSent { + border: 1px solid #c2c2c2; + border-radius: 8px 8px 0px 8px; + padding: 4px 6px; + margin: 4px 6px; + width: fit-content; + max-width: 75%; + background-color: rgba(196, 255, 211, 0.3); + min-width: 80px; + padding-bottom: 0; +} + +.messageTime { + font-size: 10px; + display: flex; + align-items: flex-end; + justify-content: flex-end; + margin-bottom: 0px; +} + +.messageContent { + margin-bottom: 0px; +} + +.createChat { + border: none; + background-color: white; +} + +.chatMessages { + margin: 10px 0; +} + +.userDetails .subtitle { + font-size: 12px; + color: #959595; + margin: 0; +} + +.userDetails .title { + font-size: 18px; + margin: 0; +} + +.contactImage { + height: fit-content; +} + +.senderInfo { + margin: 2px 2px 0px 2px; + font-size: 12px; + font-weight: 600; +} diff --git a/src/components/UserPortal/ChatRoom/ChatRoom.test.tsx b/src/components/UserPortal/ChatRoom/ChatRoom.test.tsx new file mode 100644 index 0000000000..7d72837767 --- /dev/null +++ b/src/components/UserPortal/ChatRoom/ChatRoom.test.tsx @@ -0,0 +1,907 @@ +import React from 'react'; + +import { + act, + render, + screen, + fireEvent, + waitFor, + findAllByTestId, +} from '@testing-library/react'; +import { 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 { StaticMockLink } from 'utils/StaticMockLink'; +import { + DIRECT_CHAT_BY_ID, + GROUP_CHAT_BY_ID, +} from 'GraphQl/Queries/PlugInQueries'; +import { + MESSAGE_SENT_TO_DIRECT_CHAT, + MESSAGE_SENT_TO_GROUP_CHAT, + SEND_MESSAGE_TO_DIRECT_CHAT, + SEND_MESSAGE_TO_GROUP_CHAT, +} from 'GraphQl/Mutations/OrganizationMutations'; +import userEvent from '@testing-library/user-event'; +import ChatRoom from './ChatRoom'; +import { useLocalStorage } from 'utils/useLocalstorage'; + +const { setItem } = useLocalStorage(); + +const link = new StaticMockLink([], true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const SEND_MESSAGE_TO_DIRECT_CHAT_MOCK = { + request: { + query: SEND_MESSAGE_TO_DIRECT_CHAT, + variables: { + messageContent: 'Hello', + chatId: '1', + }, + }, + result: { + data: { + sendMessageToDirectChat: { + _id: '', + createdAt: '', + messageContent: '', + receiver: { + _id: '', + firstName: '', + lastName: '', + }, + sender: { + _id: '', + firstName: '', + lastName: '', + }, + updatedAt: '', + }, + }, + }, +}; + +const SEND_MESSAGE_TO_GROUP_CHAT_MOCK = { + request: { + query: SEND_MESSAGE_TO_GROUP_CHAT, + variables: { + messageContent: 'Test message', + chatId: '1', + }, + }, + result: { + data: { + sendMessageToGroupChat: { + _id: '', + createdAt: '', + messageContent: '', + sender: { + _id: '', + firstName: '', + lastName: '', + }, + updatedAt: '', + }, + }, + }, +}; + +const MESSAGE_SENT_TO_GROUP_CHAT_MOCK = [ + { + request: { + query: MESSAGE_SENT_TO_GROUP_CHAT, + variables: { + userId: null, + }, + }, + result: { + data: { + messageSentToGroupChat: { + _id: '668ec1f1364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_GROUP_CHAT, + variables: { + userId: '2', + }, + }, + result: { + data: { + messageSentToGroupChat: { + _id: '668ec1f1df364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_GROUP_CHAT, + variables: { + userId: '1', + }, + }, + result: { + data: { + messageSentToGroupChat: { + _id: '668ec1f13603ac4697a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, +]; + +const MESSAGE_SENT_TO_DIRECT_CHAT_MOCK = [ + { + request: { + query: MESSAGE_SENT_TO_DIRECT_CHAT, + variables: { + userId: '1', + }, + }, + result: { + data: { + messageSentToDirectChat: { + _id: '668ec1f1364e03ac4697a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + image: '', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_DIRECT_CHAT, + variables: { + userId: '2', + }, + }, + result: { + data: { + messageSentToDirectChat: { + _id: '668ec1f1364e03ac4697vgfa151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + image: '', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_DIRECT_CHAT, + variables: { + userId: null, + }, + }, + result: { + data: { + messageSentToDirectChat: { + _id: '6ec1f1364e03ac4697a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + image: '', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, +]; + +const DIRECT_CHAT_BY_ID_QUERY_MOCK = [ + { + request: { + query: DIRECT_CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + directChatById: { + _id: '1', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + receiver: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: DIRECT_CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + directChatById: { + _id: '1', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + receiver: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: DIRECT_CHAT_BY_ID, + variables: { + id: '2', + }, + }, + result: { + data: { + directChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + receiver: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: DIRECT_CHAT_BY_ID, + variables: { + id: '', + }, + }, + result: { + data: { + directChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + receiver: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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 GROUP_CHAT_BY_ID_QUERY_MOCK = [ + { + request: { + query: GROUP_CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + groupChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + title: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: GROUP_CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + groupChatById: { + _id: '1', + createdAt: '2345678903456', + title: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: GROUP_CHAT_BY_ID, + variables: { + id: '2', + }, + }, + result: { + data: { + groupChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + title: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: GROUP_CHAT_BY_ID, + variables: { + id: '', + }, + }, + result: { + data: { + groupChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + title: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: '', + }, + ], + }, + }, + }, + }, +]; + +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 = [ + ...DIRECT_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_DIRECT_CHAT_MOCK, + ...MESSAGE_SENT_TO_GROUP_CHAT_MOCK, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ]; + render( + + + + + + + + + , + ); + await wait(); + expect(await screen.findByTestId('noChatSelected')).toBeInTheDocument(); + }); + + test('Selected contact is direct chat', async () => { + const mocks = [ + ...DIRECT_CHAT_BY_ID_QUERY_MOCK, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_DIRECT_CHAT_MOCK, + ...MESSAGE_SENT_TO_GROUP_CHAT_MOCK, + ]; + render( + + + + + + + + + , + ); + await wait(); + }); + + test('Test send message direct chat', async () => { + setItem('userId', '2'); + const mocks = [ + SEND_MESSAGE_TO_DIRECT_CHAT_MOCK, + ...DIRECT_CHAT_BY_ID_QUERY_MOCK, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_DIRECT_CHAT_MOCK, + ...MESSAGE_SENT_TO_GROUP_CHAT_MOCK, + ]; + 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(); + }); + }); + + test('Selected contact is group chat', async () => { + const mocks = [ + ...DIRECT_CHAT_BY_ID_QUERY_MOCK, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_DIRECT_CHAT_MOCK, + ...MESSAGE_SENT_TO_GROUP_CHAT_MOCK, + ]; + render( + + + + + + + + + , + ); + await wait(); + }); + + test('Test send message group chat', async () => { + const mocks = [ + SEND_MESSAGE_TO_GROUP_CHAT_MOCK, + ...DIRECT_CHAT_BY_ID_QUERY_MOCK, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_DIRECT_CHAT_MOCK, + ...MESSAGE_SENT_TO_GROUP_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(); + }); + }); +}); diff --git a/src/components/UserPortal/ChatRoom/ChatRoom.tsx b/src/components/UserPortal/ChatRoom/ChatRoom.tsx new file mode 100644 index 0000000000..d29de8b766 --- /dev/null +++ b/src/components/UserPortal/ChatRoom/ChatRoom.tsx @@ -0,0 +1,413 @@ +import React, { useEffect, useRef, useState } from 'react'; +import type { ChangeEvent } from 'react'; +import SendIcon from '@mui/icons-material/Send'; +import { Button, Form, InputGroup } from 'react-bootstrap'; +import styles from './ChatRoom.module.css'; +import PermContactCalendarIcon from '@mui/icons-material/PermContactCalendar'; +import { useTranslation } from 'react-i18next'; +import { + DIRECT_CHAT_BY_ID, + GROUP_CHAT_BY_ID, +} from 'GraphQl/Queries/PlugInQueries'; +import { useMutation, useQuery, useSubscription } from '@apollo/client'; +import { + MESSAGE_SENT_TO_DIRECT_CHAT, + MESSAGE_SENT_TO_GROUP_CHAT, + SEND_MESSAGE_TO_DIRECT_CHAT, + SEND_MESSAGE_TO_GROUP_CHAT, +} from 'GraphQl/Mutations/OrganizationMutations'; +import useLocalStorage from 'utils/useLocalstorage'; +import Avatar from 'components/Avatar/Avatar'; + +interface InterfaceChatRoomProps { + selectedContact: string; + selectedChatType: string; +} + +type DirectMessage = { + _id: string; + createdAt: Date; + sender: { + _id: string; + firstName: string; + lastName: string; + image: string; + }; + messageContent: string; + receiver: { + _id: string; + firstName: string; + lastName: string; + }; +}; + +type Chat = { + _id: string; + messages: { + _id: string; + createdAt: Date; + sender: { + _id: string; + firstName: string; + lastName: string; + image: string; + }; + messageContent: string; + receiver: { + _id: string; + firstName: string; + lastName: string; + }; + }[]; + users: { + _id: string; + firstName: string; + lastName: string; + email: string; + }[]; +}; + +export default function chatRoom(props: InterfaceChatRoomProps): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'userChatRoom', + }); + const isMountedRef = useRef(true); + + useEffect(() => { + return () => { + isMountedRef.current = false; + }; + }, []); + + const { getItem } = useLocalStorage(); + const userId = getItem('userId'); + const [chatTitle, setChatTitle] = useState(''); + const [chatSubtitle, setChatSubtitle] = useState(''); + const [newMessage, setNewMessage] = useState(''); + const [directChat, setDirectChat] = useState(); + const [groupChat, setGroupChat] = useState(); + + const handleNewMessageChange = (e: ChangeEvent): void => { + const newMessageValue = e.target.value; + setNewMessage(newMessageValue); + }; + + const [sendMessageToDirectChat] = useMutation(SEND_MESSAGE_TO_DIRECT_CHAT, { + variables: { + chatId: props.selectedContact, + messageContent: newMessage, + }, + }); + + const [sendMessageToGroupChat] = useMutation(SEND_MESSAGE_TO_GROUP_CHAT, { + variables: { + chatId: props.selectedContact, + messageContent: newMessage, + }, + }); + + const { + data: chatData, + loading: chatLoading, + refetch: chatRefetch, + } = useQuery(DIRECT_CHAT_BY_ID, { + variables: { + id: props.selectedContact, + }, + }); + + const { + data: chatDataGorup, + loading: groupChatLoading, + refetch: groupChatRefresh, + } = useQuery(GROUP_CHAT_BY_ID, { + variables: { + id: props.selectedContact, + }, + }); + + useEffect(() => { + if (props.selectedChatType == 'direct') { + chatRefetch(); + } else if (props.selectedChatType == 'group') { + groupChatRefresh(); + } + }, [props.selectedContact]); + + useEffect(() => { + if ( + props.selectedChatType === 'direct' && + chatData && + isMountedRef.current + ) { + const directChatData = chatData.directChatById; + setDirectChat(directChatData); + const otherUser = directChatData.users.find( + (user: any) => user._id !== userId, + ); + if (otherUser) { + setChatTitle(`${otherUser.firstName} ${otherUser.lastName}`); + setChatSubtitle(otherUser.email); + } + } + }, [chatData]); + + useEffect(() => { + if ( + props.selectedChatType === 'group' && + chatDataGorup && + isMountedRef.current + ) { + const groupChatData = chatDataGorup.groupChatById; + setGroupChat(groupChatData); + setChatTitle(groupChatData.title); + setChatSubtitle(`${groupChatData.users.length} members`); + } + }, [chatDataGorup]); + + const sendMessage = async (): Promise => { + console.log(props.selectedChatType); + if (props.selectedChatType === 'direct') { + await sendMessageToDirectChat(); + await chatRefetch(); + } else if (props.selectedChatType === 'group') { + const data = await sendMessageToGroupChat(); + await groupChatRefresh(); + } + setNewMessage(''); + }; + + useSubscription(MESSAGE_SENT_TO_DIRECT_CHAT, { + variables: { + userId: userId, + }, + onData: (directMessageSubscriptionData) => { + console.log( + directMessageSubscriptionData?.data.data.messageSentToDirectChat + .directChatMessageBelongsTo['_id'], + props.selectedContact, + ); + if ( + directMessageSubscriptionData?.data.data.messageSentToDirectChat && + directMessageSubscriptionData?.data.data.messageSentToDirectChat + .directChatMessageBelongsTo['_id'] == props.selectedContact + ) { + const updatedChat = directChat + ? JSON.parse(JSON.stringify(directChat)) + : { messages: [] }; + updatedChat?.messages.push( + directMessageSubscriptionData?.data.data.messageSentToDirectChat, + ); + setDirectChat(updatedChat); + chatRefetch(); + } + }, + }); + + useSubscription(MESSAGE_SENT_TO_GROUP_CHAT, { + variables: { + userId: userId, + }, + onData: (groupMessageSubscriptionData) => { + if ( + groupMessageSubscriptionData?.data.data.messageSentToGroupChat && + groupMessageSubscriptionData?.data.data.messageSentToGroupChat + .groupChatMessageBelongsTo['_id'] == props.selectedContact + ) { + const updatedChat = groupChat + ? JSON.parse(JSON.stringify(groupChat)) + : { messages: [] }; + updatedChat?.messages.push( + groupMessageSubscriptionData.data.data.messageSentToGroupChat, + ); + setGroupChat(updatedChat); + groupChatRefresh({ + id: props.selectedContact, + }); + } else { + groupChatRefresh({ + id: groupMessageSubscriptionData?.data.data.messageSentToGroupChat + .groupChatMessageBelongsTo['_id'], + }); + groupChatRefresh({ + id: props.selectedContact, + }); + } + }, + }); + + useEffect(() => { + document + .getElementById('chat-area') + ?.lastElementChild?.scrollIntoView({ block: 'end' }); + }); + + return ( +
    + {!props.selectedContact ? ( +
    + +
    {t('selectContact')}
    +
    + ) : ( + <> +
    +
    + +
    +

    {chatTitle}

    +

    + {chatSubtitle}{' '} + {props.selectedChatType == 'direct' ? '' : 'members'} +

    +
    +
    +
    +
    +
    + {!!( + directChat?.messages.length || groupChat?.messages.length + ) && ( +
    + {props.selectedChatType == 'direct' + ? directChat?.messages.map( + (message: DirectMessage, index: number) => { + return ( +
    +
    + + {message.messageContent} + + + {new Date( + message?.createdAt, + ).toLocaleTimeString('it-IT', { + hour: '2-digit', + minute: '2-digit', + })} + +
    +
    + ); + }, + ) + : groupChat?.messages.map( + (message: DirectMessage, index: number) => { + return ( +
    + {message.sender._id !== userId ? ( + message.sender?.image ? ( + {message.sender.image} + ) : ( + + ) + ) : ( + '' + )} +
    + {message.sender._id !== userId && ( +

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

    + )} + + {message.messageContent} + + + {new Date( + message?.createdAt, + ).toLocaleTimeString('it-IT', { + hour: '2-digit', + minute: '2-digit', + })} + +
    +
    + ); + }, + )} +
    + )} +
    +
    +
    + + + + +
    + + )} +
    + ); +} diff --git a/src/components/UserPortal/CommentCard/CommentCard.module.css b/src/components/UserPortal/CommentCard/CommentCard.module.css new file mode 100644 index 0000000000..b765d60bbd --- /dev/null +++ b/src/components/UserPortal/CommentCard/CommentCard.module.css @@ -0,0 +1,44 @@ +.mainContainer { + width: auto; + overflow: hidden; + background-color: white; + margin-top: 1rem; + padding: 0.5rem; + border: 1px solid #dddddd; + border-radius: 10px; +} + +.personDetails { + display: flex; + flex-direction: column; + justify-content: center; +} + +.personImage { + border-radius: 50%; + margin-right: 20px; +} + +.cardActions { + display: flex; + flex-direction: row; + align-items: center; + gap: 10px; + margin-top: 10px; +} + +.cardActionBtn { + background-color: rgba(0, 0, 0, 0); + border: none; + color: black; +} + +.cardActionBtn:hover { + background-color: ghostwhite; + border: none; + color: green !important; +} + +.likeIcon { + width: 20px; +} diff --git a/src/components/UserPortal/CommentCard/CommentCard.test.tsx b/src/components/UserPortal/CommentCard/CommentCard.test.tsx new file mode 100644 index 0000000000..35b81167fc --- /dev/null +++ b/src/components/UserPortal/CommentCard/CommentCard.test.tsx @@ -0,0 +1,241 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { act, 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 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'; + +const { getItem, setItem } = useLocalStorage(); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const MOCKS = [ + { + request: { + query: LIKE_COMMENT, + variables: { + commentId: '1', + }, + result: { + data: { + likeComment: { + _id: '1', + }, + }, + }, + }, + }, + { + request: { + query: UNLIKE_COMMENT, + variables: { + commentId: '1', + }, + result: { + data: { + unlikeComment: { + _id: '1', + }, + }, + }, + }, + }, +]; + +const handleLikeComment = jest.fn(); +const handleDislikeComment = jest.fn(); +const link = new StaticMockLink(MOCKS, true); + +describe('Testing CommentCard Component [User Portal]', () => { + afterEach(async () => { + await act(async () => { + await i18nForTest.changeLanguage('en'); + }); + }); + + test('Component should be rendered properly if comment is already liked by the user.', async () => { + const cardProps = { + id: '1', + creator: { + id: '1', + firstName: 'test', + lastName: 'user', + email: 'test@user.com', + }, + likeCount: 1, + likedBy: [ + { + id: '1', + }, + ], + text: 'testComment', + handleLikeComment: handleLikeComment, + handleDislikeComment: handleDislikeComment, + }; + + const beforeUserId = getItem('userId'); + setItem('userId', '2'); + + render( + + + + + + + + + , + ); + + await wait(); + if (beforeUserId) { + setItem('userId', beforeUserId); + } + }); + + test('Component should be rendered properly if comment is not already liked by the user.', async () => { + const cardProps = { + id: '1', + creator: { + id: '1', + firstName: 'test', + lastName: 'user', + email: 'test@user.com', + }, + likeCount: 1, + likedBy: [ + { + id: '1', + }, + ], + text: 'testComment', + handleLikeComment: handleLikeComment, + handleDislikeComment: handleDislikeComment, + }; + + const beforeUserId = getItem('userId'); + setItem('userId', '1'); + + render( + + + + + + + + + , + ); + + await wait(); + if (beforeUserId) { + setItem('userId', beforeUserId); + } + }); + + test('Component renders as expected if user likes the comment.', async () => { + const cardProps = { + id: '1', + creator: { + id: '1', + firstName: 'test', + lastName: 'user', + email: 'test@user.com', + }, + likeCount: 1, + likedBy: [ + { + id: '1', + }, + ], + text: 'testComment', + handleLikeComment: handleLikeComment, + handleDislikeComment: handleDislikeComment, + }; + + const beforeUserId = getItem('userId'); + setItem('userId', '2'); + + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('likeCommentBtn')); + + await wait(); + + if (beforeUserId) { + setItem('userId', beforeUserId); + } + }); + + test('Component renders as expected if user unlikes the comment.', async () => { + const cardProps = { + id: '1', + creator: { + id: '1', + firstName: 'test', + lastName: 'user', + email: 'test@user.com', + }, + likeCount: 1, + likedBy: [ + { + id: '1', + }, + ], + text: 'testComment', + handleLikeComment: handleLikeComment, + handleDislikeComment: handleDislikeComment, + }; + + const beforeUserId = getItem('userId'); + setItem('userId', '1'); + + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('likeCommentBtn')); + + if (beforeUserId) { + setItem('userId', beforeUserId); + } + }); +}); diff --git a/src/components/UserPortal/CommentCard/CommentCard.tsx b/src/components/UserPortal/CommentCard/CommentCard.tsx new file mode 100644 index 0000000000..57cc6a1cf4 --- /dev/null +++ b/src/components/UserPortal/CommentCard/CommentCard.tsx @@ -0,0 +1,111 @@ +import React from 'react'; +import { Button } from 'react-bootstrap'; +import styles from './CommentCard.module.css'; +import ThumbUpIcon from '@mui/icons-material/ThumbUp'; +import { useMutation } from '@apollo/client'; +import { LIKE_COMMENT, UNLIKE_COMMENT } from 'GraphQl/Mutations/mutations'; +import { toast } from 'react-toastify'; +import HourglassBottomIcon from '@mui/icons-material/HourglassBottom'; +import ThumbUpOffAltIcon from '@mui/icons-material/ThumbUpOffAlt'; +import useLocalStorage from 'utils/useLocalstorage'; +import AccountCircleIcon from '@mui/icons-material/AccountCircle'; + +interface InterfaceCommentCardProps { + id: string; + creator: { + id: string; + firstName: string; + lastName: string; + email: string; + }; + likeCount: number; + likedBy: { + id: string; + }[]; + text: string; + handleLikeComment: (commentId: string) => void; + handleDislikeComment: (commentId: string) => void; +} + +function commentCard(props: InterfaceCommentCardProps): JSX.Element { + const creatorName = `${props.creator.firstName} ${props.creator.lastName}`; + + const { getItem } = useLocalStorage(); + const userId = getItem('userId'); + const likedByUser = props.likedBy.some((likedBy) => likedBy.id === userId); + + const [likes, setLikes] = React.useState(props.likeCount); + const [isLikedByUser, setIsLikedByUser] = React.useState(likedByUser); + const [likeComment, { loading: likeLoading }] = useMutation(LIKE_COMMENT); + const [unlikeComment, { loading: unlikeLoading }] = + useMutation(UNLIKE_COMMENT); + + const handleToggleLike = async (): Promise => { + if (isLikedByUser) { + try { + const { data } = await unlikeComment({ + variables: { + commentId: props.id, + }, + }); + /* istanbul ignore next */ + if (data) { + setLikes((likes) => likes - 1); + setIsLikedByUser(false); + props.handleDislikeComment(props.id); + } + } catch (error: any) { + /* istanbul ignore next */ + toast.error(error); + } + } else { + try { + const { data } = await likeComment({ + variables: { + commentId: props.id, + }, + }); + /* istanbul ignore next */ + if (data) { + setLikes((likes) => likes + 1); + setIsLikedByUser(true); + props.handleLikeComment(props.id); + } + } catch (error: any) { + /* istanbul ignore next */ + toast.error(error); + } + } + }; + + return ( +
    +
    +
    + + {creatorName} +
    + {props.text} +
    + + {`${likes} Likes`} +
    +
    +
    + ); +} + +export default commentCard; diff --git a/src/components/UserPortal/ContactCard/ContactCard.module.css b/src/components/UserPortal/ContactCard/ContactCard.module.css new file mode 100644 index 0000000000..19d66596c9 --- /dev/null +++ b/src/components/UserPortal/ContactCard/ContactCard.module.css @@ -0,0 +1,37 @@ +.contact { + display: flex; + flex-direction: row; + padding: 5px 10px; + cursor: pointer; + border-radius: 10px; + /* margin-bottom: 10px; */ + /* border: 2px solid #f5f5f5; */ +} + +.contactImage { + width: 45px !important; + height: auto !important; + border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; +} + +.contactNameContainer { + display: flex; + flex-direction: column; + padding: 0px 10px; + justify-content: center; +} + +.grey { + color: grey; +} + +.bgGreen { + background-color: rgba(196, 255, 211, 0.3); +} + +.bgWhite { + background-color: white; +} diff --git a/src/components/UserPortal/ContactCard/ContactCard.test.tsx b/src/components/UserPortal/ContactCard/ContactCard.test.tsx new file mode 100644 index 0000000000..7f55196bb0 --- /dev/null +++ b/src/components/UserPortal/ContactCard/ContactCard.test.tsx @@ -0,0 +1,117 @@ +import React from 'react'; +import { act, render, screen } from '@testing-library/react'; +import { 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 { StaticMockLink } from 'utils/StaticMockLink'; +import ContactCard from './ContactCard'; +import userEvent from '@testing-library/user-event'; + +const link = new StaticMockLink([], true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +let props = { + id: '1', + title: 'Disha Talreja', + subtitle: 'disha@example.com', + email: 'noble@mittal.com', + image: '', + selectedContact: '', + type: '', + setSelectedContact: jest.fn(), + setSelectedChatType: jest.fn(), +}; + +describe('Testing ContactCard Component [User Portal]', () => { + test('Component should be rendered properly if person image is undefined', async () => { + render( + + + + + + + + + , + ); + + await wait(); + }); + + test('Component should be rendered properly if person image is not undefined', async () => { + props = { + ...props, + image: 'personImage', + }; + + render( + + + + + + + + + , + ); + + await wait(); + }); + + test('Contact gets selectected when component is clicked', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('contactContainer')); + + await wait(); + }); + + test('Component is rendered with background color grey if the contact is selected', async () => { + props = { + ...props, + selectedContact: '1', + }; + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('contactContainer')); + + await wait(); + }); +}); diff --git a/src/components/UserPortal/ContactCard/ContactCard.tsx b/src/components/UserPortal/ContactCard/ContactCard.tsx new file mode 100644 index 0000000000..69221e7583 --- /dev/null +++ b/src/components/UserPortal/ContactCard/ContactCard.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import styles from './ContactCard.module.css'; +import Avatar from 'components/Avatar/Avatar'; + +interface InterfaceContactCardProps { + id: string; + title: string; + subtitle: string; + image: string; + selectedContact: string; + setSelectedContact: React.Dispatch>; + type: string; + setSelectedChatType: React.Dispatch>; +} + +function contactCard(props: InterfaceContactCardProps): JSX.Element { + const handleSelectedContactChange = (): void => { + props.setSelectedContact(props.id); + props.setSelectedChatType(props.type); + }; + + const [isSelected, setIsSelected] = React.useState( + props.selectedContact === props.id, + ); + + React.useEffect(() => { + setIsSelected(props.selectedContact === props.id); + }, [props.selectedContact]); + + return ( + <> +
    + {props.image ? ( + {props.title} + ) : ( + + )} +
    + {props.title} + {props.subtitle} +
    +
    + + ); +} + +export default contactCard; diff --git a/src/components/UserPortal/CreateDirectChat/CreateDirectChat.module.css b/src/components/UserPortal/CreateDirectChat/CreateDirectChat.module.css new file mode 100644 index 0000000000..3795e402fa --- /dev/null +++ b/src/components/UserPortal/CreateDirectChat/CreateDirectChat.module.css @@ -0,0 +1,9 @@ +.userData { + height: 400px; + overflow-y: scroll; + overflow-x: hidden !important; +} + +.modalContent { + width: 530px; +} diff --git a/src/components/UserPortal/CreateDirectChat/CreateDirectChat.test.tsx b/src/components/UserPortal/CreateDirectChat/CreateDirectChat.test.tsx new file mode 100644 index 0000000000..b8c1dd86fb --- /dev/null +++ b/src/components/UserPortal/CreateDirectChat/CreateDirectChat.test.tsx @@ -0,0 +1,2204 @@ +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 { + DIRECT_CHATS_LIST, + 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_DIRECT_CHAT, + MESSAGE_SENT_TO_DIRECT_CHAT, + MESSAGE_SENT_TO_GROUP_CHAT, +} from 'GraphQl/Mutations/OrganizationMutations'; +import { + DIRECT_CHAT_BY_ID, + GROUP_CHAT_BY_ID, + GROUP_CHAT_LIST, +} from 'GraphQl/Queries/PlugInQueries'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem } = useLocalStorage(); + +const MOCKS = [ + { + request: { + query: GROUP_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + groupChatsByUserId: [ + { + _id: '1', + creator: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + }, + messages: { + _id: '1', + createdAt: '', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@email.com', + }, + }, + title: 'Test GroupChat', + organization: { + _id: '1', + name: 'Test Org', + }, + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@email.com', + image: 'img', + }, + ], + }, + { + _id: '2', + creator: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + }, + messages: { + _id: '1', + createdAt: '', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@email.com', + }, + }, + title: 'Test GroupChat', + organization: { + _id: '1', + name: 'Test Org', + }, + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@email.com', + image: 'img', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + groupChatsByUserId: [ + { + _id: '1', + creator: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + }, + messages: { + _id: '1', + createdAt: '', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@email.com', + }, + }, + title: 'Test GroupChat', + organization: { + _id: '1', + name: 'Test Org', + }, + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@email.com', + image: 'img', + }, + ], + }, + { + _id: '2', + creator: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + }, + messages: { + _id: '1', + createdAt: '', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@email.com', + }, + }, + title: 'Test GroupChat', + organization: { + _id: '1', + name: 'Test Org', + }, + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@email.com', + image: 'img', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + groupChatsByUserId: [ + { + _id: '1', + creator: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + }, + messages: { + _id: '1', + createdAt: '', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@email.com', + }, + }, + title: 'Test GroupChat', + organization: { + _id: '1', + name: 'Test Org', + }, + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@email.com', + image: 'img', + }, + ], + }, + { + _id: '1', + creator: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + }, + messages: { + _id: '1', + createdAt: '', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@email.com', + }, + }, + title: 'Test GroupChat', + organization: { + _id: '1', + name: 'Test Org', + }, + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@email.com', + image: 'img', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: DIRECT_CHATS_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + directChatsByUserID: [ + { + _id: '666c88dd92e995354d98527c', + creator: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '668930bae43ce54e6e302cf1', + createdAt: '2024-07-06T11:55:38.933Z', + messageContent: 'hJnkank', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + { + _id: '666f09c892e995354d98a5ee', + creator: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '6676932692e995354d98ab7f', + createdAt: '2024-06-22T09:02:30.776Z', + messageContent: 'hii', + receiver: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + ], + }, + }, + }, + { + request: { + query: DIRECT_CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + directChatsByUserID: [ + { + _id: '666c88dd92e995354d98527c', + creator: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '668930bae43ce54e6e302cf1', + createdAt: '2024-07-06T11:55:38.933Z', + messageContent: 'hJnkank', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + { + _id: '666f09c892e995354d98a5ee', + creator: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '6676932692e995354d98ab7f', + createdAt: '2024-06-22T09:02:30.776Z', + messageContent: 'hii', + receiver: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + ], + }, + }, + }, + { + request: { + query: DIRECT_CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + directChatsByUserID: [ + { + _id: '666c88dd92e995354d98527c', + creator: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '668930bae43ce54e6e302cf1', + createdAt: '2024-07-06T11:55:38.933Z', + messageContent: 'hJnkank', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + { + _id: '666f09c892e995354d98a5ee', + creator: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '6676932692e995354d98ab7f', + createdAt: '2024-06-22T09:02:30.776Z', + messageContent: 'hii', + receiver: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + ], + }, + }, + }, + { + request: { + query: DIRECT_CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + directChatsByUserID: [ + { + _id: '666c88dd92e995354d98527c', + creator: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '668930bae43ce54e6e302cf1', + createdAt: '2024-07-06T11:55:38.933Z', + messageContent: 'hJnkank', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + { + _id: '666f09c892e995354d98a5ee', + creator: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '6676932692e995354d98ab7f', + createdAt: '2024-06-22T09:02:30.776Z', + messageContent: 'hii', + receiver: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + ], + }, + }, + }, + { + request: { + query: DIRECT_CHATS_LIST, + variables: { + id: '', + }, + }, + result: { + data: { + directChatsByUserID: [ + { + _id: '666c88dd92e995354d98527c', + creator: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '668930bae43ce54e6e302cf1', + createdAt: '2024-07-06T11:55:38.933Z', + messageContent: 'hJnkank', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + { + _id: '666f09c892e995354d98a5ee', + creator: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '6676932692e995354d98ab7f', + createdAt: '2024-06-22T09:02:30.776Z', + messageContent: 'hii', + receiver: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + ], + }, + }, + }, +]; + +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', + }, + ], + }, + }, + }, + { + 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_GROUP_CHAT_MOCK = [ + { + request: { + query: MESSAGE_SENT_TO_GROUP_CHAT, + variables: { + userId: null, + }, + }, + result: { + data: { + messageSentToGroupChat: { + _id: '668ec1f1364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_GROUP_CHAT, + variables: { + userId: '2', + }, + }, + result: { + data: { + messageSentToGroupChat: { + _id: '668ec1f1df364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_GROUP_CHAT, + variables: { + userId: '1', + }, + }, + result: { + data: { + messageSentToGroupChat: { + _id: '668ec1f13603ac4697a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, +]; + +const MESSAGE_SENT_TO_DIRECT_CHAT_MOCK = [ + { + request: { + query: MESSAGE_SENT_TO_DIRECT_CHAT, + variables: { + userId: '1', + }, + }, + result: { + data: { + messageSentToDirectChat: { + _id: '668ec1f1364e03ac4697a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + image: '', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_DIRECT_CHAT, + variables: { + userId: '2', + }, + }, + result: { + data: { + messageSentToDirectChat: { + _id: '668ec1f1364e03ac4697vgfa151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + image: '', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_DIRECT_CHAT, + variables: { + userId: null, + }, + }, + result: { + data: { + messageSentToDirectChat: { + _id: '6ec1f1364e03ac4697a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + image: '', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, +]; + +const DIRECT_CHAT_BY_ID_QUERY_MOCK = [ + { + request: { + query: DIRECT_CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + directChatById: { + _id: '1', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + receiver: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: DIRECT_CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + directChatById: { + _id: '1', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + receiver: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: DIRECT_CHAT_BY_ID, + variables: { + id: '', + }, + }, + result: { + data: { + directChatById: { + _id: '1', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + receiver: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: DIRECT_CHAT_BY_ID, + variables: { + id: '2', + }, + }, + result: { + data: { + directChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + receiver: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: DIRECT_CHAT_BY_ID, + variables: { + id: null, + }, + }, + result: { + data: { + directChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + receiver: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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 GROUP_CHAT_BY_ID_QUERY_MOCK = [ + { + request: { + query: GROUP_CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + groupChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + title: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: GROUP_CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + groupChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + title: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: GROUP_CHAT_BY_ID, + variables: { + id: '', + }, + }, + result: { + data: { + groupChatById: { + _id: '1', + createdAt: '2345678903456', + title: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: GROUP_CHAT_BY_ID, + variables: { + id: '2', + }, + }, + result: { + data: { + groupChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + title: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: GROUP_CHAT_BY_ID, + variables: { + id: null, + }, + }, + result: { + data: { + groupChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + title: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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_DIRECT_CHAT_MOCK = { + request: { + query: CREATE_DIRECT_CHAT, + variables: { + userIds: ['1', '6589389d2caa9d8d69087487'], + organizationId: undefined, + }, + }, + result: { + data: { + createDirectChat: { + _id: '669394c180e96b740ba1c0ce', + __typename: 'DirectChat', + }, + }, + }, +}; + +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('Test open and close create new direct chat modal', async () => { + const mock = [ + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...DIRECT_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_DIRECT_CHAT_MOCK, + ...MESSAGE_SENT_TO_GROUP_CHAT_MOCK, + ...UserConnectionListMock, + ...MOCKS, + ]; + 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('Test create new direct chat', async () => { + setItem('userId', '1'); + const mock = [ + CREATE_DIRECT_CHAT_MOCK, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...DIRECT_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_DIRECT_CHAT_MOCK, + ...MESSAGE_SENT_TO_GROUP_CHAT_MOCK, + ...UserConnectionListMock, + ...MOCKS, + ]; + 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); + }); +}); diff --git a/src/components/UserPortal/CreateDirectChat/CreateDirectChat.tsx b/src/components/UserPortal/CreateDirectChat/CreateDirectChat.tsx new file mode 100644 index 0000000000..565dfd422f --- /dev/null +++ b/src/components/UserPortal/CreateDirectChat/CreateDirectChat.tsx @@ -0,0 +1,202 @@ +import { Paper, TableBody } from '@mui/material'; +import React, { useState } from 'react'; +import { Button, Form, Modal } from 'react-bootstrap'; +import styles from './CreateDirectChat.module.css'; +import type { ApolloQueryResult } from '@apollo/client'; +import { useMutation, useQuery } from '@apollo/client'; +import useLocalStorage from 'utils/useLocalstorage'; +import { CREATE_DIRECT_CHAT } from 'GraphQl/Mutations/OrganizationMutations'; +import Table from '@mui/material/Table'; +import TableCell, { tableCellClasses } from '@mui/material/TableCell'; +import TableContainer from '@mui/material/TableContainer'; +import TableHead from '@mui/material/TableHead'; +import TableRow from '@mui/material/TableRow'; +import { styled } from '@mui/material/styles'; +import type { InterfaceQueryUserListItem } from 'utils/interfaces'; +import { USERS_CONNECTION_LIST } from 'GraphQl/Queries/Queries'; +import Loader from 'components/Loader/Loader'; +import { Search } from '@mui/icons-material'; +import { useTranslation } from 'react-i18next'; +import { useParams } from 'react-router-dom'; + +interface InterfaceCreateDirectChatProps { + toggleCreateDirectChatModal: () => void; + createDirectChatModalisOpen: boolean; + contactRefetch: ( + variables?: + | Partial<{ + id: any; + }> + | 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, + }, +})); + +const { getItem } = useLocalStorage(); + +export default function groupChat({ + toggleCreateDirectChatModal, + createDirectChatModalisOpen, + contactRefetch, +}: InterfaceCreateDirectChatProps): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'userChat', + }); + + const { orgId: organizationId } = useParams(); + + const userId: string | null = getItem('userId'); + + const [userName, setUserName] = useState(''); + + const [createDirectChat] = useMutation(CREATE_DIRECT_CHAT); + + const handleCreateDirectChat = async (id: string): Promise => { + console.log(organizationId); + await createDirectChat({ + variables: { + organizationId, + userIds: [userId, id], + }, + }); + contactRefetch(); + toggleCreateDirectChatModal(); + }; + + const { + data: allUsersData, + loading: allUsersLoading, + refetch: allUsersRefetch, + } = useQuery(USERS_CONNECTION_LIST, { + variables: { + firstName_contains: '', + lastName_contains: '', + }, + }); + + const handleUserModalSearchChange = (e: React.FormEvent): void => { + e.preventDefault(); + /* istanbul ignore next */ + const [firstName, lastName] = userName.split(' '); + + const newFilterData = { + firstName_contains: firstName || '', + lastName_contains: lastName || '', + }; + + allUsersRefetch({ + ...newFilterData, + }); + }; + + return ( + <> + + + {'Chat'} + + + {allUsersLoading ? ( + <> + + + ) : ( + <> +
    +
    + { + const { value } = e.target; + setUserName(value); + }} + /> + + +
    + + + + + # + {'user'} + {'Chat'} + + + + {allUsersData && + allUsersData.users.length > 0 && + allUsersData.users.map( + ( + userDetails: InterfaceQueryUserListItem, + index: number, + ) => ( + + + {index + 1} + + + {userDetails.user.firstName + + ' ' + + userDetails.user.lastName} +
    + {userDetails.user.email} +
    + + + +
    + ), + )} +
    +
    +
    + + )} +
    +
    + + ); +} diff --git a/src/components/UserPortal/CreateGroupChat/CreateGroupChat.module.css b/src/components/UserPortal/CreateGroupChat/CreateGroupChat.module.css new file mode 100644 index 0000000000..3795e402fa --- /dev/null +++ b/src/components/UserPortal/CreateGroupChat/CreateGroupChat.module.css @@ -0,0 +1,9 @@ +.userData { + height: 400px; + overflow-y: scroll; + overflow-x: hidden !important; +} + +.modalContent { + width: 530px; +} diff --git a/src/components/UserPortal/CreateGroupChat/CreateGroupChat.test.tsx b/src/components/UserPortal/CreateGroupChat/CreateGroupChat.test.tsx new file mode 100644 index 0000000000..3898653f47 --- /dev/null +++ b/src/components/UserPortal/CreateGroupChat/CreateGroupChat.test.tsx @@ -0,0 +1,2746 @@ +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 { + DIRECT_CHATS_LIST, + USERS_CONNECTION_LIST, + USER_JOINED_ORGANIZATIONS, +} from 'GraphQl/Queries/Queries'; +import { BrowserRouter } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import Chat from '../../../screens/UserPortal/Chat/Chat'; +import { + CREATE_GROUP_CHAT, + MESSAGE_SENT_TO_DIRECT_CHAT, + MESSAGE_SENT_TO_GROUP_CHAT, +} from 'GraphQl/Mutations/OrganizationMutations'; +import { + DIRECT_CHAT_BY_ID, + GROUP_CHAT_BY_ID, + GROUP_CHAT_LIST, +} from 'GraphQl/Queries/PlugInQueries'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem } = useLocalStorage(); + +const MOCKS = [ + { + request: { + query: GROUP_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + groupChatsByUserId: [ + { + _id: '1', + creator: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + }, + messages: { + _id: '1', + createdAt: '', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@email.com', + }, + }, + title: 'Test GroupChat', + organization: { + _id: '1', + name: 'Test Org', + }, + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@email.com', + image: 'img', + }, + ], + }, + { + _id: '2', + creator: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + }, + messages: { + _id: '1', + createdAt: '', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@email.com', + }, + }, + title: 'Test GroupChat', + organization: { + _id: '1', + name: 'Test Org', + }, + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@email.com', + image: 'img', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + groupChatsByUserId: [ + { + _id: '1', + creator: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + }, + messages: { + _id: '1', + createdAt: '', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@email.com', + }, + }, + title: 'Test GroupChat', + organization: { + _id: '1', + name: 'Test Org', + }, + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@email.com', + image: 'img', + }, + ], + }, + { + _id: '2', + creator: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + }, + messages: { + _id: '1', + createdAt: '', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@email.com', + }, + }, + title: 'Test GroupChat', + organization: { + _id: '1', + name: 'Test Org', + }, + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@email.com', + image: 'img', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + groupChatsByUserId: [ + { + _id: '1', + creator: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + }, + messages: { + _id: '1', + createdAt: '', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@email.com', + }, + }, + title: 'Test GroupChat', + organization: { + _id: '1', + name: 'Test Org', + }, + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@email.com', + image: 'img', + }, + ], + }, + { + _id: '2', + creator: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + }, + messages: { + _id: '1', + createdAt: '', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@email.com', + }, + }, + title: 'Test GroupChat', + organization: { + _id: '1', + name: 'Test Org', + }, + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@email.com', + image: 'img', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: DIRECT_CHATS_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + directChatsByUserID: [ + { + _id: '666c88dd92e995354d98527c', + creator: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '668930bae43ce54e6e302cf1', + createdAt: '2024-07-06T11:55:38.933Z', + messageContent: 'hJnkank', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + { + _id: '666f09c892e995354d98a5ee', + creator: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '6676932692e995354d98ab7f', + createdAt: '2024-06-22T09:02:30.776Z', + messageContent: 'hii', + receiver: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + ], + }, + }, + }, + { + request: { + query: DIRECT_CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + directChatsByUserID: [ + { + _id: '666c88dd92e995354d98527c', + creator: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '668930bae43ce54e6e302cf1', + createdAt: '2024-07-06T11:55:38.933Z', + messageContent: 'hJnkank', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + { + _id: '666f09c892e995354d98a5ee', + creator: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '6676932692e995354d98ab7f', + createdAt: '2024-06-22T09:02:30.776Z', + messageContent: 'hii', + receiver: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + ], + }, + }, + }, + { + request: { + query: DIRECT_CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + directChatsByUserID: [ + { + _id: '666c88dd92e995354d98527c', + creator: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '668930bae43ce54e6e302cf1', + createdAt: '2024-07-06T11:55:38.933Z', + messageContent: 'hJnkank', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + { + _id: '666f09c892e995354d98a5ee', + creator: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '6676932692e995354d98ab7f', + createdAt: '2024-06-22T09:02:30.776Z', + messageContent: 'hii', + receiver: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + ], + }, + }, + }, + { + request: { + query: DIRECT_CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + directChatsByUserID: [ + { + _id: '666c88dd92e995354d98527c', + creator: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '668930bae43ce54e6e302cf1', + createdAt: '2024-07-06T11:55:38.933Z', + messageContent: 'hJnkank', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + { + _id: '666f09c892e995354d98a5ee', + creator: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '6676932692e995354d98ab7f', + createdAt: '2024-06-22T09:02:30.776Z', + messageContent: 'hii', + receiver: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + ], + }, + }, + }, + { + request: { + query: DIRECT_CHATS_LIST, + variables: { + id: '', + }, + }, + result: { + data: { + directChatsByUserID: [ + { + _id: '666c88dd92e995354d98527c', + creator: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '668930bae43ce54e6e302cf1', + createdAt: '2024-07-06T11:55:38.933Z', + messageContent: 'hJnkank', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + { + _id: '666f09c892e995354d98a5ee', + creator: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '6676932692e995354d98ab7f', + createdAt: '2024-06-22T09:02:30.776Z', + messageContent: 'hii', + receiver: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + ], + }, + }, + }, +]; + +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', + }, + }, + ], + }, + ], + }, + }, + ], + }, + }, + }, + { + 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: '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: 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: '2', + 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: '3', + email: 'disha@email.com', + createdAt: '', + appUserProfile: { + _id: '12', + isSuperAdmin: 'false', + createdOrganizations: { + _id: '345678', + }, + createdEvents: { + _id: '34567890', + }, + }, + organizationsBlockedBy: [], + joinedOrganizations: [], + }, + ], + }, + }, + }, + }, +]; + +const MESSAGE_SENT_TO_GROUP_CHAT_MOCK = [ + { + request: { + query: MESSAGE_SENT_TO_GROUP_CHAT, + variables: { + userId: null, + }, + }, + result: { + data: { + messageSentToGroupChat: { + _id: '668ec1f1364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_GROUP_CHAT, + variables: { + userId: '2', + }, + }, + result: { + data: { + messageSentToGroupChat: { + _id: '668ec1f1df364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_GROUP_CHAT, + variables: { + userId: '1', + }, + }, + result: { + data: { + messageSentToGroupChat: { + _id: '668ec1f13603ac4697a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, +]; + +const MESSAGE_SENT_TO_DIRECT_CHAT_MOCK = [ + { + request: { + query: MESSAGE_SENT_TO_DIRECT_CHAT, + variables: { + userId: '1', + }, + }, + result: { + data: { + messageSentToDirectChat: { + _id: '668ec1f1364e03ac4697a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + image: '', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_DIRECT_CHAT, + variables: { + userId: '2', + }, + }, + result: { + data: { + messageSentToDirectChat: { + _id: '668ec1f1364e03ac4697vgfa151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + image: '', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_DIRECT_CHAT, + variables: { + userId: null, + }, + }, + result: { + data: { + messageSentToDirectChat: { + _id: '6ec1f1364e03ac4697a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + image: '', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, +]; + +const DIRECT_CHAT_BY_ID_QUERY_MOCK = [ + { + request: { + query: DIRECT_CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + directChatById: { + _id: '1', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + receiver: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: DIRECT_CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + directChatById: { + _id: '1', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + receiver: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: DIRECT_CHAT_BY_ID, + variables: { + id: '', + }, + }, + result: { + data: { + directChatById: { + _id: '1', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + receiver: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: DIRECT_CHAT_BY_ID, + variables: { + id: '2', + }, + }, + result: { + data: { + directChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + receiver: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: DIRECT_CHAT_BY_ID, + variables: { + id: null, + }, + }, + result: { + data: { + directChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + receiver: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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 GROUP_CHAT_BY_ID_QUERY_MOCK = [ + { + request: { + query: GROUP_CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + groupChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + title: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: GROUP_CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + groupChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + title: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: GROUP_CHAT_BY_ID, + variables: { + id: '', + }, + }, + result: { + data: { + groupChatById: { + _id: '1', + createdAt: '2345678903456', + title: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: GROUP_CHAT_BY_ID, + variables: { + id: '2', + }, + }, + result: { + data: { + groupChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + title: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: GROUP_CHAT_BY_ID, + variables: { + id: null, + }, + }, + result: { + data: { + groupChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + title: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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_GROUP_CHAT_MOCK = [ + { + request: { + query: CREATE_GROUP_CHAT, + variables: { + organizationId: '6401ff65ce8e8406b8f07af2', + userIds: [null], + title: 'Test Group', + }, + }, + result: { + data: { + createGroupChat: { + _id: '669394c180e96b740ba1c0ce', + __typename: 'GroupChat', + }, + }, + }, + }, + { + request: { + query: CREATE_GROUP_CHAT, + variables: { + organizationId: '', + userIds: [null], + title: 'Test Group', + }, + }, + result: { + data: { + createGroupChat: { + _id: '669394c180e96b740ba1c0ce', + __typename: 'GroupChat', + }, + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); + +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('Test open and close create new direct chat modal', async () => { + const mock = [ + ...USER_JOINED_ORG_MOCK, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...DIRECT_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_DIRECT_CHAT_MOCK, + ...MESSAGE_SENT_TO_GROUP_CHAT_MOCK, + ...UserConnectionListMock, + ...MOCKS, + ]; + 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('Test create new group chat', async () => { + const mock = [ + ...CREATE_GROUP_CHAT_MOCK, + ...USER_JOINED_ORG_MOCK, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...DIRECT_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_DIRECT_CHAT_MOCK, + ...MESSAGE_SENT_TO_GROUP_CHAT_MOCK, + ...UserConnectionListMock, + ...MOCKS, + ]; + 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 orgSelect = screen.getByLabelText('Select Organization'); + + fireEvent.change(orgSelect, { + target: { value: '6401ff65ce8e8406b8f07af2' }, + }); + + 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('Test add and remove user ', async () => { + setItem('userId', '1'); + const mock = [ + ...USER_JOINED_ORG_MOCK, + ...CREATE_GROUP_CHAT_MOCK, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...DIRECT_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_DIRECT_CHAT_MOCK, + ...MESSAGE_SENT_TO_GROUP_CHAT_MOCK, + ...UserConnectionListMock, + ...MOCKS, + ]; + render( + + + + + + + + + , + ); + + await wait(); + + const dropdown = await screen.findByTestId('dropdown'); + expect(dropdown).toBeInTheDocument(); + fireEvent.click(dropdown); + const newGroupChatBtn = await screen.findByTestId('newGroupChat'); + expect(newGroupChatBtn).toBeInTheDocument(); + fireEvent.click(newGroupChatBtn); + + await waitFor(async () => { + expect( + await screen.findByTestId('createGroupChatModal'), + ).toBeInTheDocument(); + }); + + const nextBtn = await screen.findByTestId('nextBtn'); + + act(() => { + fireEvent.click(nextBtn); + }); + + await waitFor(async () => { + const addBtn = await screen.findAllByTestId('addBtn'); + expect(addBtn[0]).toBeInTheDocument(); + }); + + const addBtn = await screen.findAllByTestId('addBtn'); + + fireEvent.click(addBtn[0]); + + const removeBtn = await screen.findAllByText('Remove'); + await waitFor(async () => { + expect(removeBtn[0]).toBeInTheDocument(); + }); + fireEvent.click(removeBtn[0]); + + await waitFor(() => { + expect(addBtn[0]).toBeInTheDocument(); + }); + + const submitBtn = await screen.findByTestId('submitBtn'); + + expect(submitBtn).toBeInTheDocument(); + + const searchInput = (await screen.findByTestId( + 'searchUser', + )) as HTMLInputElement; + expect(searchInput).toBeInTheDocument(); + + fireEvent.change(searchInput, { target: { value: 'Disha' } }); + + expect(searchInput.value).toBe('Disha'); + + fireEvent.click(submitBtn); + + const closeButton = screen.getAllByRole('button', { name: /close/i }); + expect(closeButton[0]).toBeInTheDocument(); + + fireEvent.click(closeButton[0]); + + await wait(500); + }); +}); diff --git a/src/components/UserPortal/CreateGroupChat/CreateGroupChat.tsx b/src/components/UserPortal/CreateGroupChat/CreateGroupChat.tsx new file mode 100644 index 0000000000..29884fc2bd --- /dev/null +++ b/src/components/UserPortal/CreateGroupChat/CreateGroupChat.tsx @@ -0,0 +1,391 @@ +import { + FormControl, + FormControlLabel, + FormHelperText, + InputLabel, + MenuItem, + Paper, + RadioGroup, + Select, + FormLabel, + TableBody, + Radio, +} from '@mui/material'; +import type { SelectChangeEvent } from '@mui/material/Select'; +import React, { useEffect, useState } from 'react'; +import { Button, Form, Modal } from 'react-bootstrap'; +import styles from './CreateGroupChat.module.css'; +import type { ApolloQueryResult } from '@apollo/client'; +import { useMutation, useQuery } from '@apollo/client'; +import { USER_JOINED_ORGANIZATIONS } from 'GraphQl/Queries/OrganizationQueries'; +import useLocalStorage from 'utils/useLocalstorage'; +import { CREATE_GROUP_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 { LocalPoliceTwoTone, Search } from '@mui/icons-material'; +import { style } from '@mui/system'; +import { useTranslation } from 'react-i18next'; + +interface InterfaceCreateGroupChatProps { + toggleCreateGroupChatModal: () => void; + createGroupChatModalisOpen: boolean; + groupChatListRefetch: ( + variables?: + | Partial<{ + id: any; + }> + | 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; + }; + }[]; +} + +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, + }, +})); + +const { getItem } = useLocalStorage(); + +export default function CreateGroupChat({ + toggleCreateGroupChatModal, + createGroupChatModalisOpen, + groupChatListRefetch, +}: InterfaceCreateGroupChatProps): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'userChat', + }); + + const userId: string | null = getItem('userId'); + + const [createGroupChat] = useMutation(CREATE_GROUP_CHAT); + + const [organizations, setOrganizations] = useState([]); + const [selectedOrganization, setSelectedOrganization] = useState(''); + const [title, setTitle] = useState(''); + let [userIds, setUserIds] = useState([]); + + const [addUserModalisOpen, setAddUserModalisOpen] = useState(false); + + function openAddUserModal(): void { + setAddUserModalisOpen(true); + } + + const toggleAddUserModal = /* istanbul ignore next */ (): void => + setAddUserModalisOpen(!addUserModalisOpen); + + const handleChange = (event: React.ChangeEvent): void => { + setSelectedOrganization(event.target.value as string); + }; + + const { data: joinedOrganizationsData } = useQuery( + USER_JOINED_ORGANIZATIONS, + { + variables: { id: userId }, + }, + ); + + function reset(): void { + setOrganizations([]); + setTitle(''); + setUserIds([]); + setSelectedOrganization(''); + } + + useEffect(() => { + setUserIds(userIds); + }, [userIds]); + + async function handleCreateGroupChat(): Promise { + const groupChat = await createGroupChat({ + variables: { + organizationId: selectedOrganization, + userIds: [userId, ...userIds], + title, + }, + }); + groupChatListRefetch(); + toggleAddUserModal(); + toggleCreateGroupChatModal(); + reset(); + } + + const [userName, setUserName] = useState(''); + + const { + data: allUsersData, + loading: allUsersLoading, + refetch: allUsersRefetch, + } = useQuery(USERS_CONNECTION_LIST, { + variables: { + firstName_contains: '', + lastName_contains: '', + }, + }); + + const handleUserModalSearchChange = (e: React.FormEvent): void => { + e.preventDefault(); + /* istanbul ignore next */ + const [firstName, lastName] = userName.split(' '); + + const newFilterData = { + firstName_contains: firstName || '', + lastName_contains: lastName || '', + }; + + allUsersRefetch({ + ...newFilterData, + }); + }; + + useEffect(() => { + if (joinedOrganizationsData && joinedOrganizationsData.users.length > 0) { + const organizations = + joinedOrganizationsData.users[0]?.user?.joinedOrganizations || []; + setOrganizations(organizations); + } + }, [joinedOrganizationsData]); + + return ( + <> + + + New Group + + +
    + + Select Organization + handleChange(e)} + > + {organizations && + organizations.length && + organizations.map((organization: InterfaceOrganization) => ( + + ))} + + + + {/* + Select Organization + + */} + + Group name + { + setTitle(e.target.value); + }} + /> + + +
    +
    +
    + + + {'Chat'} + + + {allUsersLoading ? ( + <> + + + ) : ( + <> +
    +
    + { + const { value } = e.target; + setUserName(value); + }} + /> + + +
    + + + + + + # + {'user'} + {'Chat'} + + + + {allUsersData && + allUsersData.users.length > 0 && + allUsersData.users.map( + ( + userDetails: InterfaceQueryUserListItem, + index: number, + ) => ( + + + {index + 1} + + + {userDetails.user.firstName + + ' ' + + userDetails.user.lastName} +
    + {userDetails.user.email} +
    + + {userIds.includes(userDetails.user._id) ? ( + + ) : ( + + )} + +
    + ), + )} +
    +
    +
    + + )} + +
    +
    + + ); +} diff --git a/src/components/UserPortal/DonationCard/DonationCard.module.css b/src/components/UserPortal/DonationCard/DonationCard.module.css new file mode 100644 index 0000000000..3fa737ada2 --- /dev/null +++ b/src/components/UserPortal/DonationCard/DonationCard.module.css @@ -0,0 +1,41 @@ +.mainContainer { + width: 49%; + height: 8rem; + min-width: max-content; + display: flex; + justify-content: space-between; + gap: 1rem; + padding: 1rem; + background-color: white; + border: 1px solid #dddddd; + border-radius: 10px; + overflow: hidden; +} + +.img { + height: 100%; + aspect-ratio: 1/1; + background-color: rgba(49, 187, 107, 12%); +} + +.btn { + display: flex; + align-items: flex-end; +} + +.btn button { + padding-inline: 2rem !important; + border-radius: 5px; +} + +.personDetails { + display: flex; + flex-direction: column; + justify-content: center; + min-width: max-content; +} + +.personImage { + border-radius: 50%; + margin-right: 20px; +} diff --git a/src/components/UserPortal/DonationCard/DonationCard.test.tsx b/src/components/UserPortal/DonationCard/DonationCard.test.tsx new file mode 100644 index 0000000000..4e49ed8b26 --- /dev/null +++ b/src/components/UserPortal/DonationCard/DonationCard.test.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { act, render } from '@testing-library/react'; +import { 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 { StaticMockLink } from 'utils/StaticMockLink'; +import DonationCard from './DonationCard'; +import { type InterfaceDonationCardProps } from 'screens/UserPortal/Donate/Donate'; + +const link = new StaticMockLink([], true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const props: InterfaceDonationCardProps = { + id: '1', + name: 'John Doe', + amount: '20', + userId: '1234', + payPalId: 'id', + updatedAt: String(new Date()), +}; + +describe('Testing ContactCard Component [User Portal]', () => { + test('Component should be rendered properly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + }); +}); diff --git a/src/components/UserPortal/DonationCard/DonationCard.tsx b/src/components/UserPortal/DonationCard/DonationCard.tsx new file mode 100644 index 0000000000..696c5fb57b --- /dev/null +++ b/src/components/UserPortal/DonationCard/DonationCard.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import styles from './DonationCard.module.css'; +import { type InterfaceDonationCardProps } from 'screens/UserPortal/Donate/Donate'; +import { Button } from 'react-bootstrap'; + +function donationCard(props: InterfaceDonationCardProps): JSX.Element { + const date = new Date(props.updatedAt); + const formattedDate = new Intl.DateTimeFormat('en-US', { + weekday: 'short', + year: 'numeric', + month: 'short', + day: 'numeric', + }).format(date); + + return ( +
    +
    +
    + + {props.name} + + Amount: {props.amount} + Date: {formattedDate} +
    +
    + +
    +
    + ); +} + +export default donationCard; diff --git a/src/components/UserPortal/EventCard/EventCard.module.css b/src/components/UserPortal/EventCard/EventCard.module.css new file mode 100644 index 0000000000..28278dd5a6 --- /dev/null +++ b/src/components/UserPortal/EventCard/EventCard.module.css @@ -0,0 +1,26 @@ +.mainContainer { + width: 100%; + display: flex; + flex-direction: column; + padding: 10px; + cursor: pointer; + background-color: white; + border-radius: 10px; + box-shadow: 2px 2px 8px 0px #c8c8c8; + overflow: hidden; +} + +.eventDetails { + gap: 5px; +} + +.personImage { + border-radius: 50%; + margin-right: 20px; +} + +.eventActions { + display: flex; + flex-direction: row; + justify-content: right; +} diff --git a/src/components/UserPortal/EventCard/EventCard.test.tsx b/src/components/UserPortal/EventCard/EventCard.test.tsx new file mode 100644 index 0000000000..78aa32abcf --- /dev/null +++ b/src/components/UserPortal/EventCard/EventCard.test.tsx @@ -0,0 +1,194 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider } from 'react-i18next'; +import { BrowserRouter } from 'react-router-dom'; +import { ToastContainer } from 'react-toastify'; +import i18nForTest from 'utils/i18nForTest'; +import EventCard from './EventCard'; +import { render, screen, waitFor } from '@testing-library/react'; +import { REGISTER_EVENT } from 'GraphQl/Mutations/mutations'; +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(); + +const MOCKS = [ + { + request: { + query: REGISTER_EVENT, + variables: { eventId: '123' }, + }, + result: { + data: { + registerForEvent: [ + { + _id: '123', + }, + ], + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); + +afterEach(() => { + localStorage.clear(); +}); + +describe('Testing Event Card In User portal', () => { + const props = { + id: '123', + title: 'Test Event', + description: 'This is a test event', + location: 'Virtual', + startDate: '2023-04-13', + endDate: '2023-04-15', + isRegisterable: true, + isPublic: true, + endTime: '19:49:12', + startTime: '17:49:12', + recurring: false, + allDay: true, + creator: { + firstName: 'Joe', + lastName: 'David', + id: '123', + }, + registrants: [ + { + id: '234', + }, + ], + }; + + test('The card should be rendered properly, and all the details should be displayed correct', async () => { + const { queryByText } = render( + + + + + + + + + + , + ); + debug(); + await waitFor(() => expect(queryByText('Test Event')).toBeInTheDocument()); + await waitFor(() => + expect(queryByText('This is a test event')).toBeInTheDocument(), + ); + await waitFor(() => expect(queryByText('Location')).toBeInTheDocument()); + await waitFor(() => expect(queryByText('Virtual')).toBeInTheDocument()); + await waitFor(() => expect(queryByText('Starts')).toBeInTheDocument()); + await waitFor(() => + expect(screen.getByTestId('startTime')).toBeInTheDocument(), + ); + await waitFor(() => + expect(queryByText(`13 April '23`)).toBeInTheDocument(), + ); + await waitFor(() => expect(queryByText('Ends')).toBeInTheDocument()); + await waitFor(() => + expect(screen.getByTestId('endTime')).toBeInTheDocument(), + ); + await waitFor(() => + expect(queryByText(`15 April '23`)).toBeInTheDocument(), + ); + await waitFor(() => expect(queryByText('Creator')).toBeInTheDocument()); + await waitFor(() => expect(queryByText('Joe David')).toBeInTheDocument()); + await waitFor(() => expect(queryByText('Register')).toBeInTheDocument()); + }); + + test('When the user is already registered', async () => { + setItem('userId', '234'); + const { queryByText } = render( + + + + + + + + + + , + ); + await waitFor(() => + expect(queryByText('Already registered')).toBeInTheDocument(), + ); + }); + + test('Handle register should work properly', async () => { + setItem('userId', '456'); + const { queryByText } = render( + + + + + + + + + + , + ); + userEvent.click(screen.getByText('Register')); + await waitFor(() => + expect( + queryByText('Successfully registered for Test Event'), + ).toBeInTheDocument(), + ); + }); +}); + +describe('Event card when start and end time are not given', () => { + const props = { + id: '123', + title: 'Test Event', + description: 'This is a test event', + location: 'Virtual', + startDate: '2023-04-13', + endDate: '2023-04-15', + isRegisterable: true, + isPublic: true, + endTime: '', + startTime: '', + recurring: false, + allDay: true, + creator: { + firstName: 'Joe', + lastName: 'David', + id: '123', + }, + registrants: [ + { + id: '234', + }, + ], + }; + + test('Card is rendered correctly', async () => { + const { container } = render( + + + + + + + + + + , + ); + + await waitFor(() => + expect(container.querySelector(':empty')).toBeInTheDocument(), + ); + }); +}); diff --git a/src/components/UserPortal/EventCard/EventCard.tsx b/src/components/UserPortal/EventCard/EventCard.tsx new file mode 100644 index 0000000000..db8cd69785 --- /dev/null +++ b/src/components/UserPortal/EventCard/EventCard.tsx @@ -0,0 +1,132 @@ +import React from 'react'; +import styles from './EventCard.module.css'; +import CalendarMonthIcon from '@mui/icons-material/CalendarMonth'; +import dayjs from 'dayjs'; +import { Button } from 'react-bootstrap'; +import { useMutation } from '@apollo/client'; +import { toast } from 'react-toastify'; +import HourglassBottomIcon from '@mui/icons-material/HourglassBottom'; + +import { REGISTER_EVENT } from 'GraphQl/Mutations/mutations'; +import { useTranslation } from 'react-i18next'; + +import useLocalStorage from 'utils/useLocalstorage'; + +interface InterfaceEventCardProps { + id: string; + title: string; + description: string; + location: string; + startDate: string; + endDate: string; + isRegisterable: boolean; + isPublic: boolean; + endTime: string; + startTime: string; + recurring: boolean; + allDay: boolean; + creator: { + firstName: string; + lastName: string; + id: string; + }; + registrants: { + id: string; + }[]; +} + +function eventCard(props: InterfaceEventCardProps): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'userEventCard', + }); + const { t: tCommon } = useTranslation('common'); + const { getItem } = useLocalStorage(); + const userId = getItem('userId'); + const creatorName = `${props.creator.firstName} ${props.creator.lastName}`; + const isInitiallyRegistered = props.registrants.some( + (registrant) => registrant.id === userId, + ); + + const [registerEventMutation, { loading }] = useMutation(REGISTER_EVENT); + const [isRegistered, setIsRegistered] = React.useState(isInitiallyRegistered); + + const handleRegister = async (): Promise => { + if (!isRegistered) { + try { + const { data } = await registerEventMutation({ + variables: { + eventId: props.id, + }, + }); + /* istanbul ignore next */ + if (data) { + setIsRegistered(true); + toast.success(`Successfully registered for ${props.title}`); + } + } catch (error: unknown) { + /* istanbul ignore next */ + toast.error(error); + } + } + }; + + return ( +
    +
    +
    + {props.title} +
    +
    + +
    +
    + {props.description} + + {`${tCommon('location')} `} + {props.location} + +
    + {`${t('starts')} `} + {props.startTime ? ( + + {dayjs(`2015-03-04T${props.startTime}`).format('h:mm:ss A')} + + ) : ( + <> + )} + {dayjs(props.startDate).format("D MMMM 'YY")} +
    +
    + {`${t('ends')} `} + {props.endTime ? ( + + {dayjs(`2015-03-04T${props.endTime}`).format('h:mm:ss A')} + + ) : ( + <> + )}{' '} + {dayjs(props.endDate).format("D MMMM 'YY")} +
    + + {`${t('creator')} `} + {creatorName} + + +
    + {loading ? ( + + ) : isRegistered ? ( + + ) : ( + + )} +
    +
    + ); +} + +export default eventCard; diff --git a/src/components/UserPortal/OrganizationCard/OrganizationCard.module.css b/src/components/UserPortal/OrganizationCard/OrganizationCard.module.css new file mode 100644 index 0000000000..15634f7ad0 --- /dev/null +++ b/src/components/UserPortal/OrganizationCard/OrganizationCard.module.css @@ -0,0 +1,149 @@ +.orgCard { + 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; +} + +.orgCard .innerContainer { + display: flex; +} + +.orgCard .innerContainer .orgImgContainer { + display: flex; + justify-content: center; + align-items: center; + position: relative; + overflow: hidden; + border-radius: 4px; + width: 125px; + height: 120px; + object-fit: contain; + background-color: var(--bs-gray-200); +} + +.orgCard .innerContainer .content { + flex: 1; + margin-left: 1rem; + width: 70%; + margin-top: 0.7rem; +} + +.orgCard button { + position: absolute; + bottom: 1rem; + right: 1rem; + z-index: 1; +} + +.joinBtn { + display: flex; + justify-content: space-around; + width: 8rem; + border-width: medium; +} + +.joinedBtn { + display: flex; + justify-content: space-around; + width: 8rem; +} + +.withdrawBtn { + display: flex; + justify-content: space-around; + width: 8rem; +} + +.orgName { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + font-size: 1rem; +} + +.orgdesc { + font-size: 0.9rem; + color: var(--bs-gray-600); + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 1; + line-clamp: 1; + -webkit-box-orient: vertical; + max-width: 20rem; +} + +.orgadmin { + font-size: 0.9rem; +} + +.orgmember { + font-size: 0.9rem; +} + +.address { + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 1; + line-clamp: 1; + -webkit-box-orient: vertical; + align-items: center; +} + +.address h6 { + font-size: 0.9rem; + color: var(--bs-gray-600); +} + +@media (max-width: 1420px) { + .orgCard { + width: 100%; + } +} + +@media (max-width: 550px) { + .orgCard { + width: 100%; + } + + .orgCard { + height: unset; + margin: 0.5rem 0; + padding: 1.25rem 1.5rem; + } + + .orgCard .innerContainer .orgImgContainer { + margin-bottom: 0.8rem; + } + + .orgCard .innerContainer { + flex-direction: column; + } + + .orgCard .innerContainer .orgImgContainer img { + height: auto; + width: 100%; + } + + .orgCard .innerContainer .content { + margin-left: 0; + } + + .orgCard button { + bottom: 0; + right: 0; + position: relative; + margin-left: auto; + display: block; + } + .joinBtn, + .joinedBtn, + .withdrawBtn { + display: flex; + justify-content: space-around; + width: 100%; + } +} diff --git a/src/components/UserPortal/OrganizationCard/OrganizationCard.test.tsx b/src/components/UserPortal/OrganizationCard/OrganizationCard.test.tsx new file mode 100644 index 0000000000..dba4286290 --- /dev/null +++ b/src/components/UserPortal/OrganizationCard/OrganizationCard.test.tsx @@ -0,0 +1,313 @@ +import React from 'react'; +import { act, fireEvent, render, screen } from '@testing-library/react'; +import { 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 { StaticMockLink } from 'utils/StaticMockLink'; +import OrganizationCard from './OrganizationCard'; +import { + USER_JOINED_ORGANIZATIONS, + USER_ORGANIZATION_CONNECTION, +} from 'GraphQl/Queries/OrganizationQueries'; +import useLocalStorage from 'utils/useLocalstorage'; +import { + SEND_MEMBERSHIP_REQUEST, + JOIN_PUBLIC_ORGANIZATION, +} from 'GraphQl/Mutations/OrganizationMutations'; +import { toast } from 'react-toastify'; + +const { getItem } = useLocalStorage(); + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +const MOCKS = [ + { + request: { + query: SEND_MEMBERSHIP_REQUEST, + variables: { + organizationId: '1', + }, + }, + result: { + data: { + sendMembershipRequest: { + _id: 'edgwrgui4y28urfejwiwfw', + organization: { + _id: '1', + name: 'organizationName', + }, + user: { + _id: '1', + }, + }, + }, + }, + }, + { + request: { + query: JOIN_PUBLIC_ORGANIZATION, + variables: { + organizationId: '2', + }, + }, + result: { + data: { + joinPublicOrganization: { + _id: 'edgwrgui4y28urfejwiwfw', + }, + }, + }, + }, + { + request: { + query: USER_JOINED_ORGANIZATIONS, + variables: { + id: '1', + }, + }, + result: { + data: { + users: { + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '2', + image: 'organizationImage', + name: 'organizationName', + description: 'organizationDescription', + }, + ], + }, + }, + }, + }, + { + request: { + query: USER_ORGANIZATION_CONNECTION, + variables: { + id: '1', + }, + }, + result: { + data: { + organizationsConnection: [ + { + __typename: 'Organization', + _id: '2', + image: 'organizationImage', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + name: 'organizationName', + description: 'organizationDescription', + userRegistrationRequired: false, + createdAt: '12345678900', + creator: { __typename: 'User', firstName: 'John', lastName: 'Doe' }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: getItem('userId'), + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + ], + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +let props = { + id: '1', + name: 'organizationName', + image: '', + description: 'organizationDescription', + admins: [ + { + id: '123', + }, + ], + members: [], + address: { + city: 'Sample City', + countryCode: 'US', + line1: '123 Sample Street', + postalCode: '', + state: '', + }, + membershipRequestStatus: '', + userRegistrationRequired: true, + membershipRequests: [ + { + _id: '', + user: { + _id: '', + }, + }, + ], +}; + +describe('Testing OrganizationCard Component [User Portal]', () => { + test('Component should be rendered properly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + }); + + test('Component should be rendered properly if organization Image is not undefined', async () => { + props = { + ...props, + image: 'organizationImage', + }; + + render( + + + + + + + + + , + ); + + await wait(); + }); + + test('Send membership request', async () => { + props = { + ...props, + image: 'organizationImage', + }; + + render( + + + + + + + + + , + ); + + await wait(); + + expect(screen.getByTestId('joinBtn')).toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('joinBtn')); + await wait(); + + expect(toast.success).toHaveBeenCalledWith('users.MembershipRequestSent'); + }); + + test('send membership request to public org', async () => { + const cardProps = { + ...props, + id: '2', + image: 'organizationImage', + userRegistrationRequired: false, + }; + + render( + + + + + + + + + , + ); + + await wait(); + + expect(screen.getByTestId('joinBtn')).toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('joinBtn')); + await wait(); + + expect(toast.success).toHaveBeenCalledTimes(2); + }); + + test('withdraw membership request', async () => { + const cardProps = { + ...props, + id: '3', + image: 'organizationImage', + userRegistrationRequired: true, + membershipRequestStatus: 'pending', + }; + + render( + + + + + + + + + , + ); + + await wait(); + + expect(screen.getByTestId('withdrawBtn')).toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('withdrawBtn')); + }); +}); diff --git a/src/components/UserPortal/OrganizationCard/OrganizationCard.tsx b/src/components/UserPortal/OrganizationCard/OrganizationCard.tsx new file mode 100644 index 0000000000..fdb2d040d9 --- /dev/null +++ b/src/components/UserPortal/OrganizationCard/OrganizationCard.tsx @@ -0,0 +1,200 @@ +import React from 'react'; +import styles from './OrganizationCard.module.css'; +import { Button } from 'react-bootstrap'; +import { Tooltip } from '@mui/material'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; +import { + CANCEL_MEMBERSHIP_REQUEST, + JOIN_PUBLIC_ORGANIZATION, + SEND_MEMBERSHIP_REQUEST, +} from 'GraphQl/Mutations/OrganizationMutations'; +import { useMutation, useQuery } from '@apollo/client'; +import { + USER_JOINED_ORGANIZATIONS, + USER_ORGANIZATION_CONNECTION, +} from 'GraphQl/Queries/OrganizationQueries'; +import useLocalStorage from 'utils/useLocalstorage'; +import Avatar from 'components/Avatar/Avatar'; +import { useNavigate } from 'react-router-dom'; + +const { getItem } = useLocalStorage(); + +interface InterfaceOrganizationCardProps { + id: string; + name: string; + image: string; + description: string; + admins: { + id: string; + }[]; + members: { + id: string; + }[]; + address: { + city: string; + countryCode: string; + line1: string; + postalCode: string; + state: string; + }; + membershipRequestStatus: string; + userRegistrationRequired: boolean; + membershipRequests: { + _id: string; + user: { + _id: string; + }; + }[]; +} + +const userId: string | null = getItem('userId'); + +function organizationCard(props: InterfaceOrganizationCardProps): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'users', + }); + const { t: tCommon } = useTranslation('common'); + + const navigate = useNavigate(); + + const [sendMembershipRequest] = useMutation(SEND_MEMBERSHIP_REQUEST, { + refetchQueries: [ + { query: USER_ORGANIZATION_CONNECTION, variables: { id: props.id } }, + ], + }); + const [joinPublicOrganization] = useMutation(JOIN_PUBLIC_ORGANIZATION, { + refetchQueries: [ + { query: USER_ORGANIZATION_CONNECTION, variables: { id: props.id } }, + ], + }); + const [cancelMembershipRequest] = useMutation(CANCEL_MEMBERSHIP_REQUEST, { + refetchQueries: [ + { query: USER_ORGANIZATION_CONNECTION, variables: { id: props.id } }, + ], + }); + const { refetch } = useQuery(USER_JOINED_ORGANIZATIONS, { + variables: { id: userId }, + }); + + async function joinOrganization(): Promise { + try { + if (props.userRegistrationRequired) { + await sendMembershipRequest({ + variables: { + organizationId: props.id, + }, + }); + toast.success(t('MembershipRequestSent')); + } else { + await joinPublicOrganization({ + variables: { + organizationId: props.id, + }, + }); + toast.success(t('orgJoined')); + } + refetch(); + } catch (error: unknown) { + /* istanbul ignore next */ + if (error instanceof Error) { + if (error.message === 'User is already a member') { + toast.error(t('AlreadyJoined')); + } else { + toast.error(t('errorOccured')); + } + } + } + } + + async function withdrawMembershipRequest(): Promise { + const membershipRequest = props.membershipRequests.find( + (request) => request.user._id === userId, + ); + + await cancelMembershipRequest({ + variables: { + membershipRequestId: membershipRequest?._id, + }, + }); + } + + return ( + <> +
    +
    +
    + {props.image ? ( + {`${props.name} + ) : ( + + )} +
    +
    + +

    {props.name}

    +
    +
    + {props.description} +
    + {props.address && props.address.city && ( +
    +
    + {props.address.line1}, + {props.address.city}, + + {props.address.countryCode} + +
    +
    + )} +
    + {tCommon('admins')}: {props.admins?.length}   +     {tCommon('members')}:{' '} + {props.members?.length} +
    +
    +
    + {props.membershipRequestStatus === 'accepted' && ( + + )} + + {props.membershipRequestStatus === 'pending' && ( + + )} + {props.membershipRequestStatus === '' && ( + + )} +
    + + ); +} + +export default organizationCard; diff --git a/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.module.css b/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.module.css new file mode 100644 index 0000000000..761b389541 --- /dev/null +++ b/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.module.css @@ -0,0 +1,27 @@ +.talawaImage { + width: 40px; + height: auto; + margin-top: -5px; + border: 2px solid white; + margin-right: 10px; + background-color: white; + border-radius: 10px; +} + +.colorWhite { + color: white; +} + +.colorPrimary { + background: #31bb6b; +} + +.offcanvasContainer { + background-color: #31bb6b; + color: white; +} + +.link { + text-decoration: none !important; + color: inherit; +} diff --git a/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.test.tsx b/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.test.tsx new file mode 100644 index 0000000000..027234b641 --- /dev/null +++ b/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.test.tsx @@ -0,0 +1,452 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import 'jest-localstorage-mock'; +import { act, render, screen } from '@testing-library/react'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter, Router } from 'react-router-dom'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; +import cookies from 'js-cookie'; +import { StaticMockLink } from 'utils/StaticMockLink'; + +import OrganizationNavbar from './OrganizationNavbar'; +import userEvent from '@testing-library/user-event'; +import { USER_ORGANIZATION_CONNECTION } from 'GraphQl/Queries/Queries'; +import { PLUGIN_SUBSCRIPTION } from 'GraphQl/Mutations/mutations'; + +import { createMemoryHistory } from 'history'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem, removeItem } = useLocalStorage(); + +const organizationId = 'org1234'; + +const MOCK_ORGANIZATION_CONNECTION = { + request: { + query: USER_ORGANIZATION_CONNECTION, + variables: { + id: organizationId, + }, + }, + result: { + data: { + organizationsConnection: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + image: '', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + name: 'anyOrganization1', + description: 'desc', + userRegistrationRequired: true, + createdAt: '12345678900', + creator: { __typename: 'User', firstName: 'John', lastName: 'Doe' }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + ], + }, + }, +}; + +const MOCKS = [MOCK_ORGANIZATION_CONNECTION]; + +const PLUGIN_SUBSCRIPTION_1 = [ + MOCK_ORGANIZATION_CONNECTION, + { + request: { + query: PLUGIN_SUBSCRIPTION, + }, + result: { + data: { + onPluginUpdate: { + pluginName: 'TestPlugin1', + _id: '123', + pluginDesc: 'desc', + uninstalledOrgs: [organizationId], + }, + }, + _loadingSub: false, + }, + }, +]; + +const PLUGIN_SUBSCRIPTION_2 = [ + MOCK_ORGANIZATION_CONNECTION, + { + request: { + query: PLUGIN_SUBSCRIPTION, + }, + result: { + data: { + onPluginUpdate: { + pluginName: 'TestPlugin1', + _id: '123', + pluginDesc: 'desc', + uninstalledOrgs: [], + }, + }, + _loadingSub: false, + }, + }, +]; + +const PLUGIN_SUBSCRIPTION_3 = [ + MOCK_ORGANIZATION_CONNECTION, + { + request: { + query: PLUGIN_SUBSCRIPTION, + }, + result: { + data: { + onPluginUpdate: { + pluginName: 'TestPlugin100', + _id: '123', + pluginDesc: 'desc', + uninstalledOrgs: [organizationId], + }, + }, + _loadingSub: false, + }, + }, +]; + +const testPlugins = [ + { + pluginName: 'TestPlugin1', + alias: 'testPlugin1', + link: '/testPlugin1', + translated: 'Test Plugin 1', + view: true, + }, +]; + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(PLUGIN_SUBSCRIPTION_1, true); +const link3 = new StaticMockLink(PLUGIN_SUBSCRIPTION_2, true); +const link4 = new StaticMockLink(PLUGIN_SUBSCRIPTION_3, true); + +const navbarProps = { + currentPage: 'home', +}; + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: organizationId }), +})); + +describe('Testing OrganizationNavbar Component [User Portal]', () => { + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // Deprecated + removeListener: jest.fn(), // Deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), + }); + + afterEach(async () => { + await act(async () => { + await i18nForTest.changeLanguage('en'); + }); + }); + + test('Component should be rendered properly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + expect(screen.queryByText('anyOrganization1')).toBeInTheDocument(); + // Check if navigation links are rendered + expect(screen.getByText('Home')).toBeInTheDocument(); + expect(screen.getByText('People')).toBeInTheDocument(); + expect(screen.getByText('Events')).toBeInTheDocument(); + expect(screen.getByText('Donate')).toBeInTheDocument(); + // expect(screen.getByText('Chat')).toBeInTheDocument(); + }); + + test('should navigate correctly on clicking a plugin', async () => { + const history = createMemoryHistory(); + render( + + + + + + + + + , + ); + + const peoplePlugin = screen.getByText('People'); + expect(peoplePlugin).toBeInTheDocument(); + + userEvent.click(peoplePlugin); + + await wait(); + expect(history.location.pathname).toBe(`/user/people/${organizationId}`); + }); + + test('The language is switched to English', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('languageIcon')); + + userEvent.click(screen.getByTestId('changeLanguageBtn0')); + + await wait(); + + expect(cookies.get('i18next')).toBe('en'); + // Check if navigation links are rendered + expect(screen.getByText('Home')).toBeInTheDocument(); + expect(screen.getByText('People')).toBeInTheDocument(); + expect(screen.getByText('Events')).toBeInTheDocument(); + expect(screen.getByText('Donate')).toBeInTheDocument(); + // expect(screen.getByText('Chat')).toBeInTheDocument(); + }); + + test('The language is switched to fr', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('languageIcon')); + + userEvent.click(screen.getByTestId('changeLanguageBtn1')); + + await wait(); + + expect(cookies.get('i18next')).toBe('fr'); + }); + + test('The language is switched to hi', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('languageIcon')); + + userEvent.click(screen.getByTestId('changeLanguageBtn2')); + + await wait(); + + expect(cookies.get('i18next')).toBe('hi'); + }); + + test('The language is switched to sp', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('languageIcon')); + + userEvent.click(screen.getByTestId('changeLanguageBtn3')); + + await wait(); + + expect(cookies.get('i18next')).toBe('sp'); + }); + + test('The language is switched to zh', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('languageIcon')); + + userEvent.click(screen.getByTestId('changeLanguageBtn4')); + + await wait(); + + expect(cookies.get('i18next')).toBe('zh'); + }); + + test('Component should be rendered properly if plugins are present in localStorage', async () => { + setItem('talawaPlugins', JSON.stringify(testPlugins)); + + render( + + + + + + + + + , + ); + + await wait(); + + testPlugins.forEach((plugin) => { + expect(screen.queryByText(plugin.translated)).toBeInTheDocument(); + }); + + removeItem('talawaPlugins'); + }); + + test('should remove plugin if uninstalledOrgs contains organizationId', async () => { + setItem('talawaPlugins', JSON.stringify(testPlugins)); + + render( + + + + + + + + + , + ); + + await wait(); + + testPlugins.forEach((plugin) => { + expect(screen.queryByText(plugin.translated)).not.toBeInTheDocument(); + }); + }); + + test('should render plugin if uninstalledOrgs does not contain organizationId', async () => { + setItem('talawaPlugins', JSON.stringify(testPlugins)); + + render( + + + + + + + + + , + ); + + await wait(); + + testPlugins.forEach((plugin) => { + expect(screen.queryByText(plugin.translated)).toBeInTheDocument(); + }); + }); + + test('should do nothing if pluginName is not found in the rendered plugins', async () => { + render( + + + + + + + + + , + ); + + await wait(); + }); +}); diff --git a/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.tsx b/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.tsx new file mode 100644 index 0000000000..90cd75a83c --- /dev/null +++ b/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.tsx @@ -0,0 +1,247 @@ +import React from 'react'; +import styles from './OrganizationNavbar.module.css'; +import TalawaImage from 'assets/images/talawa-logo-200x200.png'; +import { Container, Dropdown, Nav, Navbar, Offcanvas } from 'react-bootstrap'; +import { languages } from 'utils/languages'; +import i18next from 'i18next'; +import cookies from 'js-cookie'; +import PermIdentityIcon from '@mui/icons-material/PermIdentity'; +import LanguageIcon from '@mui/icons-material/Language'; +import { useTranslation } from 'react-i18next'; +import { useQuery, useSubscription } from '@apollo/client'; +import { USER_ORGANIZATION_CONNECTION } from 'GraphQl/Queries/Queries'; +import type { DropDirection } from 'react-bootstrap/esm/DropdownContext'; +import { Link, useNavigate, useParams } from 'react-router-dom'; +import { PLUGIN_SUBSCRIPTION } from 'GraphQl/Mutations/mutations'; +import useLocalStorage from 'utils/useLocalstorage'; +interface InterfaceNavbarProps { + currentPage: string | null; +} + +type Plugin = { + pluginName: string; + + alias: string; + link: string; + translated: string; + view: boolean; +}; +function organizationNavbar(props: InterfaceNavbarProps): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'userNavbar', + }); + const { t: tCommon } = useTranslation('common'); + + const navigate = useNavigate(); + + const [organizationDetails, setOrganizationDetails] = React.useState<{ + name: string; + }>({ name: '' }); + // const dropDirection: DropDirection = screen.width > 767 ? 'start' : 'down'; + const dropDirection: DropDirection = 'start'; + + const { orgId: organizationId } = useParams(); + + const { data } = useQuery(USER_ORGANIZATION_CONNECTION, { + variables: { id: organizationId }, + }); + + const [currentLanguageCode, setCurrentLanguageCode] = React.useState( + /* istanbul ignore next */ + cookies.get('i18next') || 'en', + ); + + const { getItem, setItem } = useLocalStorage(); + + /* istanbul ignore next */ + const handleLogout = (): void => { + localStorage.clear(); + window.location.replace('/'); + }; + + const userName = getItem('name'); + React.useEffect(() => { + if (data) { + setOrganizationDetails({ name: data.organizationsConnection[0].name }); + } + }, [data]); + + const homeLink = `/user/organization/${organizationId}`; + let plugins: Plugin[] = [ + { + pluginName: 'People', + alias: 'people', + link: `/user/people/${organizationId}`, + translated: t('people'), + view: true, + }, + { + pluginName: 'Events', + alias: 'events', + link: `/user/events/${organizationId}`, + translated: t('events'), + view: true, + }, + { + pluginName: 'Donation', + alias: 'donate', + link: `/user/donate/${organizationId}`, + translated: t('donate'), + view: true, + }, + // { + // pluginName: 'Chats', + // alias: 'chat', + // link: `/user/chat/id=${organizationId}`, + // translated: t('chat'), + // view: true, + // }, + ]; + if (getItem('talawaPlugins')) { + const talawaPlugins: string = getItem('talawaPlugins') || '{}'; + plugins = JSON.parse(talawaPlugins); + } + + const { data: updatedPluginData } = useSubscription( + PLUGIN_SUBSCRIPTION, + // { variables: { } } + ); + function getPluginIndex(pluginName: string, pluginsArray: Plugin[]): number { + return pluginsArray.findIndex((plugin) => plugin.pluginName === pluginName); + } + + if (updatedPluginData != undefined) { + const pluginName = updatedPluginData.onPluginUpdate.pluginName; + const uninstalledOrgs = updatedPluginData.onPluginUpdate.uninstalledOrgs; + const pluginIndexToRemove = getPluginIndex(pluginName, plugins); + if (uninstalledOrgs.includes(organizationId)) { + if (pluginIndexToRemove != -1) { + plugins[pluginIndexToRemove].view = false; + setItem('talawaPlugins', JSON.stringify(plugins)); + console.log(`Plugin ${pluginName} has been removed.`); + } else { + console.log(`Plugin ${pluginName} is not present.`); + } + } else { + if (pluginIndexToRemove != -1) { + plugins[pluginIndexToRemove].view = true; + setItem('talawaPlugins', JSON.stringify(plugins)); + } + } + } + return ( + + + + Talawa Branding + {organizationDetails.name} + + + + + Talawa + + + + + + + + + + {languages.map((language, index: number) => ( + => { + setCurrentLanguageCode(language.code); + await i18next.changeLanguage(language.code); + }} + disabled={currentLanguageCode === language.code} + data-testid={`changeLanguageBtn${index}`} + > + {' '} + {language.name} + + ))} + + + + + + + + + + {userName} + + + + {tCommon('settings')} + + + + {tCommon('logout')} + + + + + + + + + ); +} + +export default organizationNavbar; diff --git a/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.module.css b/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.module.css new file mode 100644 index 0000000000..cf8bc84dda --- /dev/null +++ b/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.module.css @@ -0,0 +1,76 @@ +.mainContainer { + display: flex; + overflow: auto; + flex-direction: column; + /* align-items: center; */ + padding: 20px; + /* padding-top: 20px; */ + width: 250px; + flex-grow: 1; + background-color: var(--bs-white); +} + +@media screen and (max-width: 900px) { + .mainContainer { + display: none; + } +} + +.userDetails { + display: flex; + flex-direction: column; + align-items: center; + padding-top: 20px; +} + +.boxShadow { + box-shadow: 4px 4px 8px 4px #c8c8c8; +} + +.organizationsConatiner { + width: 100%; + padding-top: 50px; +} + +.heading { + padding: 10px 0px; +} + +.orgName { + font-size: 16px; + font-weight: 600; + margin-top: 4px; + margin-left: 5px; +} + +.alignRight { + width: 100%; + text-align: right; + padding: 5px; +} + +.link { + text-decoration: none !important; + color: black; +} + +.rounded { + border-radius: 10px !important; +} + +.colorLight { + background-color: #f5f5f5; +} + +.marginTop { + margin-top: -2px; +} + +.eventDetails { + font-size: small; + gap: 5px; +} + +.memberImage { + border-radius: 50%; +} diff --git a/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.test.tsx b/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.test.tsx new file mode 100644 index 0000000000..c5fbcf335e --- /dev/null +++ b/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.test.tsx @@ -0,0 +1,159 @@ +import React from 'react'; +import { act, render, screen } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider } from 'react-i18next'; + +import { + ORGANIZATIONS_MEMBER_CONNECTION_LIST, + ORGANIZATION_EVENT_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 { StaticMockLink } from 'utils/StaticMockLink'; +import OrganizationSidebar from './OrganizationSidebar'; + +const MOCKS = [ + { + request: { + query: ORGANIZATION_EVENT_CONNECTION_LIST, + variables: { + organization_id: 'events', + first: 3, + skip: 0, + }, + }, + result: { + data: { + eventsByOrganizationConnection: [ + { + _id: 1, + title: 'Event', + description: 'Event Test', + startDate: '', + endDate: '', + location: 'New Delhi', + startTime: '02:00', + endTime: '06:00', + allDay: false, + recurring: false, + recurrenceRule: null, + isRecurringEventException: false, + isPublic: true, + isRegisterable: true, + }, + ], + }, + }, + }, + { + request: { + query: ORGANIZATIONS_MEMBER_CONNECTION_LIST, + variables: { + orgId: 'members', + first: 3, + skip: 0, + }, + }, + result: { + data: { + organizationsMemberConnection: { + edges: [ + { + _id: '64001660a711c62d5b4076a2', + firstName: 'Noble', + lastName: 'Mittal', + image: null, + email: 'noble@gmail.com', + createdAt: '2023-03-02T03:22:08.101Z', + }, + { + _id: '64001660a711c62d5b4076a3', + firstName: 'Noble', + lastName: 'Mittal', + image: 'mockImage', + email: 'noble@gmail.com', + createdAt: '2023-03-02T03:22:08.101Z', + }, + ], + }, + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} +let mockId = ''; +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: mockId }), +})); + +describe('Testing OrganizationSidebar Component [User Portal]', () => { + test('Component should be rendered properly when members and events list is empty', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + expect(screen.queryByText('No Members to show')).toBeInTheDocument(); + expect(screen.queryByText('No Events to show')).toBeInTheDocument(); + }); + + test('Component should be rendered properly when events list is not empty', async () => { + mockId = 'events'; + render( + + + + + + + + + , + ); + + await wait(); + expect(screen.queryByText('No Members to show')).toBeInTheDocument(); + expect(screen.queryByText('No Events to show')).not.toBeInTheDocument(); + expect(screen.queryByText('Event')).toBeInTheDocument(); + }); + + test('Component should be rendered properly when members list is not empty', async () => { + mockId = 'members'; + render( + + + + + + + + + , + ); + + await wait(); + expect(screen.queryByText('No Members to show')).not.toBeInTheDocument(); + expect(screen.queryByText('No Events to show')).toBeInTheDocument(); + }); +}); diff --git a/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.tsx b/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.tsx new file mode 100644 index 0000000000..ede5e0a103 --- /dev/null +++ b/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.tsx @@ -0,0 +1,166 @@ +import React, { useEffect } from 'react'; +import { ListGroup } from 'react-bootstrap'; +import AboutImg from 'assets/images/defaultImg.png'; +import styles from './OrganizationSidebar.module.css'; +import ChevronRightIcon from '@mui/icons-material/ChevronRight'; +import { Link, useParams } from 'react-router-dom'; +import { useQuery } from '@apollo/client'; +import { + ORGANIZATIONS_MEMBER_CONNECTION_LIST, + ORGANIZATION_EVENT_CONNECTION_LIST, +} from 'GraphQl/Queries/Queries'; +import HourglassBottomIcon from '@mui/icons-material/HourglassBottom'; +import CalendarMonthIcon from '@mui/icons-material/CalendarMonth'; +import dayjs from 'dayjs'; +import { useTranslation } from 'react-i18next'; +import type { + InterfaceQueryOrganizationEventListItem, + InterfaceMemberInfo, +} from 'utils/interfaces'; +import { skip } from 'node:test'; + +export default function organizationSidebar(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'organizationSidebar', + }); + const { t: tCommon } = useTranslation('common'); + + const { orgId: organizationId } = useParams(); + const [members, setMembers] = React.useState< + InterfaceMemberInfo[] | undefined + >(undefined); + const [events, setEvents] = React.useState< + InterfaceQueryOrganizationEventListItem[] | undefined + >(undefined); + const eventsLink = `/user/events/${organizationId}`; + const peopleLink = `/user/people/${organizationId}`; + + const { data: memberData, loading: memberLoading } = useQuery( + ORGANIZATIONS_MEMBER_CONNECTION_LIST, + { + variables: { + orgId: organizationId, + first: 3, + skip: 0, + }, + }, + ); + + const { data: eventsData, loading: eventsLoading } = useQuery( + ORGANIZATION_EVENT_CONNECTION_LIST, + { + variables: { + organization_id: organizationId, + first: 3, + skip: 0, + }, + }, + ); + + /* istanbul ignore next */ + useEffect(() => { + if (memberData) { + setMembers(memberData.organizationsMemberConnection.edges); + } + }, [memberData]); + + /* istanbul ignore next */ + useEffect(() => { + if (eventsData) { + setEvents(eventsData.eventsByOrganizationConnection); + } + }, [eventsData]); + + return ( +
    +
    + {tCommon('members')} +
    + {memberLoading ? ( +
    + Loading... +
    + ) : ( + + {members && members.length ? ( + members.map((member: InterfaceMemberInfo) => { + const memberName = `${member.firstName} ${member.lastName}`; + return ( + +
    + +
    {memberName}
    +
    +
    + ); + }) + ) : ( +
    {t('noMembers')}
    + )} +
    + )} + +
    + + {t('viewAll')} + + +
    +
    + {t('events')} +
    + {eventsLoading ? ( +
    + Loading... +
    + ) : ( + + {events && events.length ? ( + events.map((event: InterfaceQueryOrganizationEventListItem) => { + return ( + +
    +
    +
    {event.title}
    +
    + +
    +
    +
    + Starts{' '} + {dayjs(event.startDate).format("D MMMM 'YY")} +
    +
    + Ends {dayjs(event.endDate).format("D MMMM 'YY")} +
    +
    +
    + ); + }) + ) : ( +
    {t('noEvents')}
    + )} +
    + )} +
    + + {t('viewAll')} + + +
    +
    + ); +} diff --git a/src/components/UserPortal/PeopleCard/PeopleCard.module.css b/src/components/UserPortal/PeopleCard/PeopleCard.module.css new file mode 100644 index 0000000000..fe9fc3bcbd --- /dev/null +++ b/src/components/UserPortal/PeopleCard/PeopleCard.module.css @@ -0,0 +1,33 @@ +.mainContainer { + width: 100%; + display: flex; + flex-direction: row; + padding: 10px; + cursor: pointer; + background-color: white; + border-radius: 10px; + box-shadow: 2px 2px 8px 0px #c8c8c8; + overflow: hidden; +} + +.personDetails { + display: flex; + flex-direction: column; + justify-content: center; +} + +.personImage { + border-radius: 50%; + margin-right: 20px; + max-width: 70px; +} + +.borderBox { + border: 1px solid #dddddd; + box-shadow: 5px 5px 4px 0px #31bb6b1f; + border-radius: 4px; +} + +.greenText { + color: #31bb6b; +} diff --git a/src/components/UserPortal/PeopleCard/PeopleCard.test.tsx b/src/components/UserPortal/PeopleCard/PeopleCard.test.tsx new file mode 100644 index 0000000000..5cadfa923b --- /dev/null +++ b/src/components/UserPortal/PeopleCard/PeopleCard.test.tsx @@ -0,0 +1,69 @@ +import React from 'react'; +import { act, render } from '@testing-library/react'; +import { 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 { StaticMockLink } from 'utils/StaticMockLink'; +import PeopleCard from './PeopleCard'; + +const link = new StaticMockLink([], true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +let props = { + id: '1', + name: 'First Last', + image: '', + email: 'first@last.com', + role: 'Admin', + sno: '1', +}; + +describe('Testing PeopleCard Component [User Portal]', () => { + test('Component should be rendered properly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + }); + + test('Component should be rendered properly if person image is not undefined', async () => { + props = { + ...props, + image: 'personImage', + }; + + render( + + + + + + + + + , + ); + + await wait(); + }); +}); diff --git a/src/components/UserPortal/PeopleCard/PeopleCard.tsx b/src/components/UserPortal/PeopleCard/PeopleCard.tsx new file mode 100644 index 0000000000..ec06122359 --- /dev/null +++ b/src/components/UserPortal/PeopleCard/PeopleCard.tsx @@ -0,0 +1,47 @@ +import React from 'react'; +import aboutImg from 'assets/images/defaultImg.png'; +import styles from './PeopleCard.module.css'; + +interface InterfaceOrganizationCardProps { + id: string; + name: string; + image: string; + email: string; + role: string; + sno: string; +} + +function peopleCard(props: InterfaceOrganizationCardProps): JSX.Element { + const imageUrl = props.image ? props.image : aboutImg; + + return ( +
    + + + {props.sno} + + + + + + + {props.name} + + + {props.email} + +
    +
    + {props.role} +
    +
    +
    + ); +} + +export default peopleCard; diff --git a/src/components/UserPortal/PostCard/PostCard.module.css b/src/components/UserPortal/PostCard/PostCard.module.css new file mode 100644 index 0000000000..e8edc2d82c --- /dev/null +++ b/src/components/UserPortal/PostCard/PostCard.module.css @@ -0,0 +1,183 @@ +.cardStyles { + width: 20rem; + background-color: white; + padding: 0; + border: none !important; + outline: none !important; +} + +.cardHeader { + display: flex; + width: 100%; + padding-inline: 0; + padding-block: 0; + flex-direction: row; + gap: 0.5rem; + align-items: center; + background-color: white; + border-bottom: 1px solid #dddddd; +} + +.creator { + display: flex; + width: 100%; + padding-inline: 1rem; + padding-block: 0; + flex-direction: row; + gap: 0.5rem; + align-items: center; +} +.creator p { + margin-bottom: 0; + font-weight: 500; +} +.creator svg { + width: 2rem; + height: 2rem; +} + +.customToggle { + padding: 0; + background: none; + border: none; + margin-right: 1rem; + --bs-btn-active-bg: none; +} +.customToggle svg { + color: black; +} + +.customToggle::after { + content: none; +} +.customToggle:hover, +.customToggle:focus, +.customToggle:active { + background: none; + border: none; +} +.customToggle svg { + color: black; +} + +.cardBody div { + padding: 0.5rem; +} + +.imageContainer { + max-width: 100%; +} + +.cardTitle { + --max-lines: 1; + display: -webkit-box; + overflow: hidden; + -webkit-box-orient: vertical; + -webkit-line-clamp: var(--max-lines); + + font-size: 1.3rem !important; + font-weight: 600; +} + +.date { + font-weight: 600; +} + +.cardText { + --max-lines: 2; + display: -webkit-box; + overflow: hidden; + -webkit-box-orient: vertical; + -webkit-line-clamp: var(--max-lines); + + padding-top: 0; + font-weight: 300; + margin-top: 0.7rem !important; + text-align: justify; +} + +.viewBtn { + display: flex; + justify-content: flex-end; + margin: 0.5rem; +} +.viewBtn Button { + padding-inline: 1rem; +} + +.cardActions { + display: flex; + flex-direction: row; + align-items: center; + gap: 1px; + justify-content: flex-end; +} + +.cardActionBtn { + background-color: rgba(0, 0, 0, 0); + padding: 0; + border: none; + color: black; +} + +.cardActionBtn:hover { + background-color: ghostwhite; + border: none; + color: black !important; +} + +.creatorNameModal { + display: flex; + flex-direction: row; + gap: 5px; + align-items: center; + margin-bottom: 10px; +} + +.modalActions { + display: flex; + flex-direction: row; + align-items: center; + gap: 1rem; + margin: 5px 0px; +} + +.textModal { + margin-top: 10px; +} + +.colorPrimary { + background: #31bb6b; + color: white; + cursor: pointer; +} + +.commentContainer { + overflow: auto; + max-height: 18rem; + padding-bottom: 1rem; +} + +.modalFooter { + background-color: white; + position: absolute; + width: calc(100% - 1rem); + padding-block: 0.5rem; + display: flex; + flex-direction: column; + border-top: 1px solid #dddddd; + bottom: 0; + right: 0.5rem; + margin-left: 1rem; +} + +.inputArea { + border: none; + outline: none; + background-color: #f1f3f6; +} + +.postImage { + height: 300px; + object-fit: cover; +} diff --git a/src/components/UserPortal/PostCard/PostCard.test.tsx b/src/components/UserPortal/PostCard/PostCard.test.tsx new file mode 100644 index 0000000000..64f6670223 --- /dev/null +++ b/src/components/UserPortal/PostCard/PostCard.test.tsx @@ -0,0 +1,861 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { act, 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 i18nForTest from 'utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { toast } from 'react-toastify'; + +import PostCard from './PostCard'; +import userEvent from '@testing-library/user-event'; +import { + CREATE_COMMENT_POST, + LIKE_POST, + UNLIKE_POST, + LIKE_COMMENT, + UNLIKE_COMMENT, + DELETE_POST_MUTATION, + UPDATE_POST_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem, getItem } = useLocalStorage(); + +jest.mock('react-toastify', () => ({ + toast: { + error: jest.fn(), + info: jest.fn(), + success: jest.fn(), + }, +})); + +const MOCKS = [ + { + request: { + query: LIKE_POST, + variables: { + postId: '', + }, + result: { + data: { + likePost: { + _id: '', + }, + }, + }, + }, + }, + { + request: { + query: UNLIKE_POST, + variables: { + post: '', + }, + result: { + data: { + unlikePost: { + _id: '', + }, + }, + }, + }, + }, + { + request: { + query: CREATE_COMMENT_POST, + variables: { + postId: '1', + comment: 'testComment', + }, + result: { + data: { + createComment: { + _id: '64ef885bca85de60ebe0f304', + creator: { + _id: '63d6064458fce20ee25c3bf7', + firstName: 'Noble', + lastName: 'Mittal', + email: 'test@gmail.com', + __typename: 'User', + }, + likeCount: 0, + likedBy: [], + text: 'testComment', + __typename: 'Comment', + }, + }, + }, + }, + }, + { + request: { + query: LIKE_COMMENT, + variables: { + commentId: '1', + }, + }, + result: { + data: { + likeComment: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: UNLIKE_COMMENT, + variables: { + commentId: '1', + }, + }, + result: { + data: { + unlikeComment: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: UPDATE_POST_MUTATION, + variables: { + id: 'postId', + text: 'Edited Post', + }, + }, + result: { + data: { + updatePost: { + _id: '', + }, + }, + }, + }, + { + request: { + query: DELETE_POST_MUTATION, + variables: { + id: 'postId', + }, + }, + result: { + data: { + removePost: { + _id: '', + }, + }, + }, + }, +]; + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const link = new StaticMockLink(MOCKS, true); + +describe('Testing PostCard Component [User Portal]', () => { + test('Component should be rendered properly', async () => { + const cardProps = { + id: 'postId', + userImage: 'image.png', + creator: { + firstName: 'test', + lastName: 'user', + email: 'test@user.com', + id: '1', + }, + postedAt: '', + image: '', + video: '', + text: 'This is post test text', + title: 'This is post test title', + likeCount: 1, + commentCount: 1, + comments: [ + { + id: '64eb13beca85de60ebe0ed0e', + creator: { + id: '63d6064458fce20ee25c3bf7', + firstName: 'Noble', + lastName: 'Mittal', + email: 'test@gmail.com', + __typename: 'User', + }, + likeCount: 0, + likedBy: [], + text: 'First comment from Talawa user portal.', + __typename: 'Comment', + }, + { + id: '64eb13beca85de60ebe0ed0b', + creator: { + id: '63d6064458fce20ee25c3bf8', + firstName: 'Priyanshu', + lastName: 'Bartwal', + email: 'test1@gmail.com', + __typename: 'User', + }, + likeCount: 0, + likedBy: [], + text: 'First comment from Talawa user portal.', + __typename: 'Comment', + }, + ], + likedBy: [ + { + firstName: '', + lastName: '', + id: '2', + }, + ], + fetchPosts: jest.fn(), + }; + + render( + + + + + + + + + , + ); + + await wait(); + }); + + test('Dropdown component should be rendered properly', async () => { + setItem('userId', '2'); + + const cardProps = { + id: '', + userImage: 'image.png', + creator: { + firstName: 'test', + lastName: 'user', + email: 'test@user.com', + id: '1', + }, + postedAt: '', + image: '', + video: '', + text: 'This is post test text', + title: 'This is post test title', + likeCount: 1, + commentCount: 0, + comments: [], + likedBy: [ + { + firstName: 'test', + lastName: 'user', + id: '2', + }, + ], + fetchPosts: jest.fn(), + }; + + render( + + + + + + + + + , + ); + await wait(); + + userEvent.click(screen.getByTestId('dropdown')); + await wait(); + expect(screen.getByText('Edit')).toBeInTheDocument(); + expect(screen.getByText('Delete')).toBeInTheDocument(); + }); + + test('Edit post should work properly', async () => { + setItem('userId', '2'); + + const cardProps = { + id: 'postId', + userImage: 'image.png', + creator: { + firstName: 'test', + lastName: 'user', + email: 'test@user.com', + id: '1', + }, + postedAt: '', + image: '', + video: '', + text: 'test Post', + title: 'This is post test title', + likeCount: 1, + commentCount: 0, + comments: [], + likedBy: [ + { + firstName: 'test', + lastName: 'user', + id: '2', + }, + ], + fetchPosts: jest.fn(), + }; + + render( + + + + + + + + + , + ); + await wait(); + + userEvent.click(screen.getByTestId('dropdown')); + userEvent.click(screen.getByTestId('editPost')); + await wait(); + + expect(screen.getByTestId('editPostModalTitle')).toBeInTheDocument(); + userEvent.clear(screen.getByTestId('postInput')); + userEvent.type(screen.getByTestId('postInput'), 'Edited Post'); + userEvent.click(screen.getByTestId('editPostBtn')); + await wait(); + + expect(toast.success).toBeCalledWith('Post updated Successfully'); + }); + + test('Delete post should work properly', async () => { + setItem('userId', '2'); + + const cardProps = { + id: 'postId', + userImage: 'image.png', + creator: { + firstName: 'test', + lastName: 'user', + email: 'test@user.com', + id: '1', + }, + postedAt: '', + image: '', + video: '', + text: 'test Post', + title: 'This is post test title', + likeCount: 1, + commentCount: 0, + comments: [], + likedBy: [ + { + firstName: 'test', + lastName: 'user', + id: '2', + }, + ], + fetchPosts: jest.fn(), + }; + + render( + + + + + + + + + , + ); + await wait(); + + userEvent.click(screen.getByTestId('dropdown')); + userEvent.click(screen.getByTestId('deletePost')); + await wait(); + + expect(toast.success).toBeCalledWith('Successfully deleted the Post.'); + }); + + test('Component should be rendered properly if user has liked the post', async () => { + const beforeUserId = getItem('userId'); + setItem('userId', '2'); + + const cardProps = { + id: '', + userImage: 'image.png', + creator: { + firstName: 'test', + lastName: 'user', + email: 'test@user.com', + id: '1', + }, + postedAt: '', + image: '', + video: '', + text: 'This is post test text', + title: 'This is post test title', + likeCount: 1, + commentCount: 0, + comments: [], + likedBy: [ + { + firstName: 'test', + lastName: 'user', + id: '2', + }, + ], + fetchPosts: jest.fn(), + }; + + render( + + + + + + + + + , + ); + + await wait(); + + if (beforeUserId) { + setItem('userId', beforeUserId); + } + }); + + test('Component should be rendered properly if user unlikes a post', async () => { + const beforeUserId = getItem('userId'); + setItem('userId', '2'); + + const cardProps = { + id: '', + userImage: 'image.png', + creator: { + firstName: 'test', + lastName: 'user', + email: 'test@user.com', + id: '1', + }, + postedAt: '', + image: '', + video: '', + text: 'This is post test text', + title: 'This is post test title', + likeCount: 1, + commentCount: 0, + comments: [], + likedBy: [ + { + firstName: 'test', + lastName: 'user', + id: '2', + }, + ], + fetchPosts: jest.fn(), + }; + + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('viewPostBtn')); + userEvent.click(screen.getByTestId('likePostBtn')); + + if (beforeUserId) { + setItem('userId', beforeUserId); + } + }); + + test('Component should be rendered properly if user likes a post', async () => { + const beforeUserId = getItem('userId'); + setItem('userId', '2'); + + const cardProps = { + id: '', + userImage: 'image.png', + creator: { + firstName: 'test', + lastName: 'user', + email: 'test@user.com', + id: '1', + }, + postedAt: '', + image: '', + video: '', + text: 'This is post test text', + title: 'This is post test title', + likeCount: 1, + commentCount: 0, + comments: [], + likedBy: [ + { + firstName: 'test', + lastName: 'user', + id: '1', + }, + ], + fetchPosts: jest.fn(), + }; + + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('viewPostBtn')); + userEvent.click(screen.getByTestId('likePostBtn')); + + if (beforeUserId) { + setItem('userId', beforeUserId); + } + }); + + test('Component should be rendered properly if post image is defined', async () => { + const cardProps = { + id: '', + userImage: 'image.png', + creator: { + firstName: 'test', + lastName: 'user', + email: 'test@user.com', + id: '1', + }, + postedAt: '', + image: 'testImage', + video: '', + text: 'This is post test text', + title: 'This is post test title', + likeCount: 1, + commentCount: 0, + comments: [], + likedBy: [ + { + firstName: 'test', + lastName: 'user', + id: '1', + }, + ], + fetchPosts: jest.fn(), + }; + + render( + + + + + + + + + , + ); + + await wait(); + }); + + test('Comment is created successfully after create comment button is clicked.', async () => { + const cardProps = { + id: '1', + userImage: 'image.png', + creator: { + firstName: 'test', + lastName: 'user', + email: 'test@user.com', + id: '1', + }, + postedAt: '', + image: 'testImage', + video: '', + text: 'This is post test text', + title: 'This is post test title', + likeCount: 1, + commentCount: 0, + comments: [], + likedBy: [ + { + firstName: 'test', + lastName: 'user', + id: '1', + }, + ], + fetchPosts: jest.fn(), + }; + + render( + + + + + + + + + , + ); + + const randomComment = 'testComment'; + + userEvent.click(screen.getByTestId('viewPostBtn')); + + userEvent.type(screen.getByTestId('commentInput'), randomComment); + userEvent.click(screen.getByTestId('createCommentBtn')); + + await wait(); + }); + + test(`Comment should be liked when like button is clicked`, async () => { + const cardProps = { + id: '1', + creator: { + firstName: 'test', + lastName: 'user', + email: 'test@user.com', + id: '1', + }, + image: 'testImage', + video: '', + text: 'This is post test text', + title: 'This is post test title', + likeCount: 1, + commentCount: 1, + postedAt: '', + comments: [ + { + id: '1', + creator: { + _id: '1', + id: '1', + firstName: 'test', + lastName: 'user', + email: 'test@user.com', + }, + likeCount: 1, + likedBy: [ + { + id: '1', + }, + ], + text: 'testComment', + }, + { + id: '2', + creator: { + _id: '1', + id: '1', + firstName: 'test', + lastName: 'user', + email: 'test@user.com', + }, + likeCount: 1, + likedBy: [ + { + id: '2', + }, + ], + text: 'testComment', + }, + ], + likedBy: [ + { + firstName: 'test', + lastName: 'user', + id: '1', + }, + ], + fetchPosts: jest.fn(), + }; + const beforeUserId = getItem('userId'); + setItem('userId', '2'); + + render( + + + + + + + + + , + ); + + userEvent.click(screen.getByTestId('viewPostBtn')); + + userEvent.click(screen.getAllByTestId('likeCommentBtn')[0]); + + await wait(); + + if (beforeUserId) { + setItem('userId', beforeUserId); + } + }); + + test(`Comment should be unliked when like button is clicked, if already liked`, async () => { + const cardProps = { + id: '1', + creator: { + firstName: 'test', + lastName: 'user', + email: 'test@user.com', + id: '1', + }, + image: 'testImage', + video: '', + text: 'This is post test text', + title: 'This is post test title', + likeCount: 1, + commentCount: 1, + postedAt: '', + comments: [ + { + id: '1', + creator: { + _id: '1', + id: '1', + firstName: 'test', + lastName: 'user', + email: 'test@user.com', + }, + likeCount: 1, + likedBy: [ + { + id: '1', + }, + ], + text: 'testComment', + }, + { + id: '2', + creator: { + _id: '1', + id: '1', + firstName: 'test', + lastName: 'user', + email: 'test@user.com', + }, + likeCount: 1, + likedBy: [ + { + id: '2', + }, + ], + text: 'testComment', + }, + ], + likedBy: [ + { + firstName: 'test', + lastName: 'user', + id: '1', + }, + ], + fetchPosts: jest.fn(), + }; + const beforeUserId = getItem('userId'); + setItem('userId', '1'); + + render( + + + + + + + + + , + ); + + userEvent.click(screen.getByTestId('viewPostBtn')); + + userEvent.click(screen.getAllByTestId('likeCommentBtn')[0]); + + await wait(); + + if (beforeUserId) { + setItem('userId', beforeUserId); + } + }); + test('Comment modal pops when show comments button is clicked.', async () => { + const cardProps = { + id: '', + userImage: 'image.png', + creator: { + firstName: 'test', + lastName: 'user', + email: 'test@user.com', + id: '1', + }, + postedAt: '', + image: 'testImage', + video: '', + text: 'This is post test text', + title: 'This is post test title', + likeCount: 1, + commentCount: 0, + comments: [], + likedBy: [ + { + firstName: 'test', + lastName: 'user', + id: '1', + }, + ], + fetchPosts: jest.fn(), + }; + + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('viewPostBtn')); + expect(screen.findAllByText('Comments')).not.toBeNull(); + }); +}); diff --git a/src/components/UserPortal/PostCard/PostCard.tsx b/src/components/UserPortal/PostCard/PostCard.tsx new file mode 100644 index 0000000000..d1bfbb1391 --- /dev/null +++ b/src/components/UserPortal/PostCard/PostCard.tsx @@ -0,0 +1,448 @@ +import React from 'react'; +import { useMutation } from '@apollo/client'; +import { toast } from 'react-toastify'; +import { useTranslation } from 'react-i18next'; +import { + Col, + Button, + Card, + Dropdown, + Form, + InputGroup, + Modal, + ModalFooter, +} from 'react-bootstrap'; +import AccountCircleIcon from '@mui/icons-material/AccountCircle'; +import HourglassBottomIcon from '@mui/icons-material/HourglassBottom'; +import ThumbUpOffAltIcon from '@mui/icons-material/ThumbUpOffAlt'; +import SendIcon from '@mui/icons-material/Send'; +import MoreVertIcon from '@mui/icons-material/MoreVert'; +import ThumbUpIcon from '@mui/icons-material/ThumbUp'; +import CommentIcon from '@mui/icons-material/Comment'; +import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined'; +import EditOutlinedIcon from '@mui/icons-material/EditOutlined'; + +import type { InterfacePostCard } from 'utils/interfaces'; +import { + CREATE_COMMENT_POST, + DELETE_POST_MUTATION, + LIKE_POST, + UNLIKE_POST, + UPDATE_POST_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import CommentCard from '../CommentCard/CommentCard'; +import { errorHandler } from 'utils/errorHandler'; +import useLocalStorage from 'utils/useLocalstorage'; +import styles from './PostCard.module.css'; +import UserDefault from '../../../assets/images/defaultImg.png'; + +interface InterfaceCommentCardProps { + id: string; + creator: { + id: string; + firstName: string; + lastName: string; + email: string; + }; + likeCount: number; + likedBy: { + id: string; + }[]; + text: string; + handleLikeComment: (commentId: string) => void; + handleDislikeComment: (commentId: string) => void; +} + +export default function postCard(props: InterfacePostCard): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'postCard', + }); + const { t: tCommon } = useTranslation('common'); + + const { getItem } = useLocalStorage(); + + const userId = getItem('userId'); + const likedByUser = props.likedBy.some((likedBy) => likedBy.id === userId); + const [comments, setComments] = React.useState(props.comments); + const [numComments, setNumComments] = React.useState(props.commentCount); + + const [likes, setLikes] = React.useState(props.likeCount); + const [isLikedByUser, setIsLikedByUser] = React.useState(likedByUser); + const [commentInput, setCommentInput] = React.useState(''); + const [viewPost, setViewPost] = React.useState(false); + const [showEditPost, setShowEditPost] = React.useState(false); + const [postContent, setPostContent] = React.useState(props.text); + + const postCreator = `${props.creator.firstName} ${props.creator.lastName}`; + + const [likePost, { loading: likeLoading }] = useMutation(LIKE_POST); + const [unLikePost, { loading: unlikeLoading }] = useMutation(UNLIKE_POST); + const [create, { loading: commentLoading }] = + useMutation(CREATE_COMMENT_POST); + const [editPost] = useMutation(UPDATE_POST_MUTATION); + const [deletePost] = useMutation(DELETE_POST_MUTATION); + + const toggleViewPost = (): void => setViewPost(!viewPost); + const toggleEditPost = (): void => setShowEditPost(!showEditPost); + const handlePostInput = (e: React.ChangeEvent): void => { + setPostContent(e.target.value); + }; + + const handleToggleLike = async (): Promise => { + if (isLikedByUser) { + try { + const { data } = await unLikePost({ + variables: { + postId: props.id, + }, + }); + /* istanbul ignore next */ + if (data) { + setLikes((likes) => likes - 1); + setIsLikedByUser(false); + } + } catch (error: unknown) { + /* istanbul ignore next */ + toast.error(error); + } + } else { + try { + const { data } = await likePost({ + variables: { + postId: props.id, + }, + }); + /* istanbul ignore next */ + if (data) { + setLikes((likes) => likes + 1); + setIsLikedByUser(true); + } + } catch (error: unknown) { + /* istanbul ignore next */ + toast.error(error); + } + } + }; + + const handleCommentInput = ( + event: React.ChangeEvent, + ): void => { + const comment = event.target.value; + setCommentInput(comment); + }; + + const handleDislikeComment = (commentId: string): void => { + const updatedComments = comments.map((comment) => { + let updatedComment = { ...comment }; + if ( + comment.id === commentId && + comment.likedBy.some((user) => user.id === userId) + ) { + updatedComment = { + ...comment, + likedBy: comment.likedBy.filter((user) => user.id !== userId), + likeCount: comment.likeCount - 1, + }; + } + return updatedComment; + }); + setComments(updatedComments); + }; + const handleLikeComment = (commentId: string): void => { + const updatedComments = comments.map((comment) => { + let updatedComment = { ...comment }; + if ( + comment.id === commentId && + !comment.likedBy.some((user) => user.id === userId) + ) { + updatedComment = { + ...comment, + likedBy: [...comment.likedBy, { id: userId }], + likeCount: comment.likeCount + 1, + }; + } + return updatedComment; + }); + setComments(updatedComments); + }; + + const createComment = async (): Promise => { + try { + const { data: createEventData } = await create({ + variables: { + postId: props.id, + comment: commentInput, + }, + }); + + /* istanbul ignore next */ + if (createEventData) { + setCommentInput(''); + setNumComments((numComments) => numComments + 1); + + const newComment: InterfaceCommentCardProps = { + id: createEventData.createComment.id, + creator: { + id: createEventData.createComment.creator._id, + firstName: createEventData.createComment.creator.firstName, + lastName: createEventData.createComment.creator.lastName, + email: createEventData.createComment.creator.email, + }, + likeCount: createEventData.createComment.likeCount, + likedBy: createEventData.createComment.likedBy, + text: createEventData.createComment.text, + handleLikeComment: handleLikeComment, + handleDislikeComment: handleDislikeComment, + }; + + setComments([...comments, newComment]); + } + } catch (error: unknown) { + /* istanbul ignore next */ + errorHandler(t, error); + } + }; + + const handleEditPost = (): void => { + try { + editPost({ + variables: { + id: props.id, + text: postContent, + }, + }); + + props.fetchPosts(); + toggleEditPost(); + toast.success(tCommon('updatedSuccessfully', { item: 'Post' })); + } catch (error: unknown) { + /* istanbul ignore next */ + errorHandler(t, error); + } + }; + const handleDeletePost = (): void => { + try { + deletePost({ + variables: { + id: props.id, + }, + }); + + props.fetchPosts(); + toast.success('Successfully deleted the Post.'); + } catch (error: unknown) { + /* istanbul ignore next */ + errorHandler(t, error); + } + }; + + return ( + + + +
    + +

    {postCreator}

    +
    + + + + + + + + {tCommon('edit')} + + + + {tCommon('delete')} + + {/* Pin Post + Report + Share */} + + +
    + + + + {props.title} + + + {t('postedOn', { date: props.postedAt })} + + + {props.text} + + + +
    + +
    +
    +
    + + +
    + postImg +
    +
    +
    +
    + +

    {postCreator}

    +
    +
    + +
    +
    +
    +

    + {props.title} +

    +

    {props.text}

    +
    +

    Comments

    +
    + {numComments ? ( + comments.map((comment, index: number) => { + const cardProps: InterfaceCommentCardProps = { + id: comment.id, + creator: { + id: comment.creator.id, + firstName: comment.creator.firstName, + lastName: comment.creator.lastName, + email: comment.creator.email, + }, + likeCount: comment.likeCount, + likedBy: comment.likedBy, + text: comment.text, + handleLikeComment: handleLikeComment, + handleDislikeComment: handleDislikeComment, + }; + return ; + }) + ) : ( +

    No comments to show.

    + )} +
    +
    +
    +
    + + {likes} + {` ${t('likes')}`} +
    +
    + + {numComments} + {` ${t('comments')}`} +
    +
    + + + + {commentLoading ? ( + + ) : ( + + )} + + +
    +
    +
    +
    + + +

    + {t('editPost')} +

    +
    + + + + + + +
    + + ); +} diff --git a/src/components/UserPortal/PromotedPost/PromotedPost.module.css b/src/components/UserPortal/PromotedPost/PromotedPost.module.css new file mode 100644 index 0000000000..676d30a83a --- /dev/null +++ b/src/components/UserPortal/PromotedPost/PromotedPost.module.css @@ -0,0 +1,61 @@ +.cardActions { + display: flex; + flex-direction: row; + align-items: center; + gap: 1px; +} + +.cardActionBtn { + background-color: rgba(0, 0, 0, 0); + border: none; + color: black; +} + +.cardActionBtn:hover { + background-color: ghostwhite; + border: none; + color: black !important; +} + +.imageContainer { + max-width: 100%; +} + +.cardHeader { + display: flex; + flex-direction: row; + gap: 10px; + align-items: center; + color: #50c878; +} + +.creatorNameModal { + display: flex; + flex-direction: row; + gap: 5px; + align-items: center; + margin-bottom: 10px; +} + +.modalActions { + display: flex; + flex-direction: row; + align-items: center; + gap: 1px; + margin: 5px 0px; +} + +.textModal { + margin-top: 10px; +} + +.colorPrimary { + background: #31bb6b; + color: white; + cursor: pointer; +} + +.admedia { + object-fit: cover; + height: 30rem; +} diff --git a/src/components/UserPortal/PromotedPost/PromotedPost.test.tsx b/src/components/UserPortal/PromotedPost/PromotedPost.test.tsx new file mode 100644 index 0000000000..b5d753551c --- /dev/null +++ b/src/components/UserPortal/PromotedPost/PromotedPost.test.tsx @@ -0,0 +1,127 @@ +import React from 'react'; +import { act, render, waitFor } from '@testing-library/react'; +import { 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 { StaticMockLink } from 'utils/StaticMockLink'; +import PromotedPost from './PromotedPost'; + +const link = new StaticMockLink([], true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +let props = { + id: '1', + image: '', + title: 'Test Post', +}; + +describe('Testing PromotedPost Test', () => { + test('Component should be rendered properly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + }); + + test('Component should be rendered properly if prop image is not undefined', async () => { + props = { + ...props, + image: 'promotedPostImage', + }; + + render( + + + + + + + + + , + ); + + await wait(); + }); +}); + +test('Component should display the icon correctly', async () => { + const { queryByTestId } = render( + + + + + + + + + , + ); + + await waitFor(() => { + const icon = queryByTestId('StarPurple500Icon'); + expect(icon).toBeInTheDocument(); + }); +}); + +test('Component should display the text correctly', async () => { + const { queryAllByText } = render( + + + + + + + + + , + ); + + await waitFor(() => { + const title = queryAllByText('Test Post') as HTMLElement[]; + expect(title[0]).toBeInTheDocument(); + }); +}); + +test('Component should display the image correctly', async () => { + props = { + ...props, + image: 'promotedPostImage', + }; + const { queryByRole } = render( + + + + + + + + + , + ); + + await waitFor(() => { + const image = queryByRole('img'); + expect(image).toHaveAttribute('src', 'promotedPostImage'); + }); +}); diff --git a/src/components/UserPortal/PromotedPost/PromotedPost.tsx b/src/components/UserPortal/PromotedPost/PromotedPost.tsx new file mode 100644 index 0000000000..72ee107217 --- /dev/null +++ b/src/components/UserPortal/PromotedPost/PromotedPost.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { Card } from 'react-bootstrap'; +import styles from './PromotedPost.module.css'; +import StarPurple500Icon from '@mui/icons-material/StarPurple500'; +interface InterfacePostCardProps { + id: string; + image: string; + title: string; +} +export default function promotedPost( + props: InterfacePostCardProps, +): JSX.Element { + return ( + <> + + +
    + + {'Promoted Content'} +
    +
    + + {props.title} + {props.title} + {props.image && ( + + )} + +
    + + ); +} diff --git a/src/components/UserPortal/Register/Register.module.css b/src/components/UserPortal/Register/Register.module.css new file mode 100644 index 0000000000..1fc2a34af2 --- /dev/null +++ b/src/components/UserPortal/Register/Register.module.css @@ -0,0 +1,15 @@ +.loginText { + cursor: pointer; +} + +.borderNone { + border: none; +} + +.colorWhite { + color: white; +} + +.colorPrimary { + background: #31bb6b; +} diff --git a/src/components/UserPortal/Register/Register.test.tsx b/src/components/UserPortal/Register/Register.test.tsx new file mode 100644 index 0000000000..cdcfb9ebc0 --- /dev/null +++ b/src/components/UserPortal/Register/Register.test.tsx @@ -0,0 +1,267 @@ +import type { SetStateAction } from 'react'; +import React from 'react'; +import { act, render, screen } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import userEvent from '@testing-library/user-event'; +import { I18nextProvider } from 'react-i18next'; +import { SIGNUP_MUTATION } from 'GraphQl/Mutations/mutations'; +import { BrowserRouter } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import Register from './Register'; +import { toast } from 'react-toastify'; + +const MOCKS = [ + { + request: { + query: SIGNUP_MUTATION, + variables: { + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@gmail.com', + password: 'johnDoe', + }, + }, + result: { + data: { + signUp: { + user: { + _id: '1', + }, + accessToken: 'accessToken', + refreshToken: 'refreshToken', + }, + }, + }, + }, +]; + +const formData = { + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@gmail.com', + password: 'johnDoe', + confirmPassword: 'johnDoe', +}; + +const link = new StaticMockLink(MOCKS, true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }, +})); + +const setCurrentMode: React.Dispatch> = jest.fn(); + +const props = { + setCurrentMode, +}; + +describe('Testing Register Component [User Portal]', () => { + test('Component should be rendered properly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + }); + + test('Expect the mode to be changed to Login', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('setLoginBtn')); + + expect(setCurrentMode).toBeCalledWith('login'); + }); + + test('Expect toast.error to be called if email input is empty', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('registerBtn')); + + expect(toast.error).toBeCalledWith('Please enter valid details.'); + }); + + test('Expect toast.error to be called if password input is empty', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.type(screen.getByTestId('emailInput'), formData.email); + userEvent.click(screen.getByTestId('registerBtn')); + + expect(toast.error).toBeCalledWith('Please enter valid details.'); + }); + + test('Expect toast.error to be called if first name input is empty', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.type(screen.getByTestId('passwordInput'), formData.password); + + userEvent.type(screen.getByTestId('emailInput'), formData.email); + + userEvent.click(screen.getByTestId('registerBtn')); + + expect(toast.error).toBeCalledWith('Please enter valid details.'); + }); + + test('Expect toast.error to be called if last name input is empty', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.type(screen.getByTestId('passwordInput'), formData.password); + + userEvent.type(screen.getByTestId('emailInput'), formData.email); + + userEvent.type(screen.getByTestId('firstNameInput'), formData.firstName); + + userEvent.click(screen.getByTestId('registerBtn')); + + expect(toast.error).toBeCalledWith('Please enter valid details.'); + }); + + test("Expect toast.error to be called if confirmPassword doesn't match with password", async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.type(screen.getByTestId('passwordInput'), formData.password); + + userEvent.type(screen.getByTestId('emailInput'), formData.email); + + userEvent.type(screen.getByTestId('firstNameInput'), formData.firstName); + + userEvent.type(screen.getByTestId('lastNameInput'), formData.lastName); + + userEvent.click(screen.getByTestId('registerBtn')); + + expect(toast.error).toBeCalledWith( + "Password doesn't match. Confirm Password and try again.", + ); + }); + + test('Expect toast.success to be called if valid credentials are entered.', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.type(screen.getByTestId('passwordInput'), formData.password); + + userEvent.type( + screen.getByTestId('confirmPasswordInput'), + formData.confirmPassword, + ); + + userEvent.type(screen.getByTestId('emailInput'), formData.email); + + userEvent.type(screen.getByTestId('firstNameInput'), formData.firstName); + + userEvent.type(screen.getByTestId('lastNameInput'), formData.lastName); + + userEvent.click(screen.getByTestId('registerBtn')); + + await wait(); + + expect(toast.success).toBeCalledWith( + 'Successfully registered. Please wait for admin to approve your request.', + ); + }); +}); diff --git a/src/components/UserPortal/Register/Register.tsx b/src/components/UserPortal/Register/Register.tsx new file mode 100644 index 0000000000..a9a4a52d85 --- /dev/null +++ b/src/components/UserPortal/Register/Register.tsx @@ -0,0 +1,222 @@ +import type { ChangeEvent, SetStateAction } from 'react'; +import React from 'react'; +import { Button, Form, InputGroup } from 'react-bootstrap'; +import EmailOutlinedIcon from '@mui/icons-material/EmailOutlined'; +import BadgeOutlinedIcon from '@mui/icons-material/BadgeOutlined'; +import { LockOutlined } from '@mui/icons-material'; +import { useTranslation } from 'react-i18next'; +import { SIGNUP_MUTATION } from 'GraphQl/Mutations/mutations'; + +import styles from './Register.module.css'; +import { useMutation } from '@apollo/client'; +import { toast } from 'react-toastify'; +import { errorHandler } from 'utils/errorHandler'; + +interface InterfaceRegisterProps { + setCurrentMode: React.Dispatch>; +} + +export default function register(props: InterfaceRegisterProps): JSX.Element { + const { setCurrentMode } = props; + + const { t } = useTranslation('translation', { keyPrefix: 'userRegister' }); + const { t: tCommon } = useTranslation('common'); + + const handleModeChangeToLogin = (): void => { + setCurrentMode('login'); + }; + + const [registerMutation] = useMutation(SIGNUP_MUTATION); + + const [registerVariables, setRegisterVariables] = React.useState({ + firstName: '', + lastName: '', + email: '', + password: '', + confirmPassword: '', + }); + + const handleRegister = async (): Promise => { + if ( + !( + registerVariables.email && + registerVariables.password && + registerVariables.firstName && + registerVariables.lastName + ) + ) { + toast.error(t('invalidDetailsMessage')); + } else if ( + registerVariables.password !== registerVariables.confirmPassword + ) { + toast.error(t('passwordNotMatch')); + } else { + try { + await registerMutation({ + variables: { + firstName: registerVariables.firstName, + lastName: registerVariables.lastName, + email: registerVariables.email, + password: registerVariables.password, + }, + }); + + toast.success(t('afterRegister')); + + /* istanbul ignore next */ + setRegisterVariables({ + firstName: '', + lastName: '', + email: '', + password: '', + confirmPassword: '', + }); + } catch (error: unknown) { + /* istanbul ignore next */ + errorHandler(t, error); + } + } + }; + + /* istanbul ignore next */ + const handleFirstName = (e: ChangeEvent): void => { + const firstName = e.target.value; + + setRegisterVariables({ ...registerVariables, firstName }); + }; + + /* istanbul ignore next */ + const handleLastName = (e: ChangeEvent): void => { + const lastName = e.target.value; + + setRegisterVariables({ ...registerVariables, lastName }); + }; + + /* istanbul ignore next */ + const handleEmailChange = (e: ChangeEvent): void => { + const email = e.target.value; + + setRegisterVariables({ ...registerVariables, email }); + }; + + /* istanbul ignore next */ + const handlePasswordChange = (e: ChangeEvent): void => { + const password = e.target.value; + + setRegisterVariables({ ...registerVariables, password }); + }; + + /* istanbul ignore next */ + const handleConfirmPasswordChange = ( + e: ChangeEvent, + ): void => { + const confirmPassword = e.target.value; + + setRegisterVariables({ ...registerVariables, confirmPassword }); + }; + + return ( + <> +

    {tCommon('register')}

    +
    +
    {tCommon('firstName')}
    + + + + + + +
    {tCommon('lastName')}
    + + + + + + +
    {tCommon('emailAddress')}
    + + + + + + +
    {tCommon('password')}
    + + + + + + +
    {tCommon('confirmPassword')}
    + + + + + + +
    + + +
    + {t('alreadyhaveAnAccount')}{' '} + + {tCommon('login')} + +
    + + ); +} diff --git a/src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.test.tsx b/src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.test.tsx new file mode 100644 index 0000000000..93b71b14f1 --- /dev/null +++ b/src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.test.tsx @@ -0,0 +1,96 @@ +import React from 'react'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; +import { render, screen, waitFor } from '@testing-library/react'; +import SecuredRouteForUser from './SecuredRouteForUser'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem } = useLocalStorage(); + +describe('SecuredRouteForUser', () => { + test('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'); + + render( + + + }> + + Organizations Component +
    + } + /> + + + , + ); + + expect(screen.getByTestId('organizations-content')).toBeInTheDocument(); + }); + + test('redirects to /user when the user is not logged in', async () => { + // Set the user as not logged in in local storage + setItem('IsLoggedIn', 'FALSE'); + + render( + + + User Login Page
    } /> + }> + + Organizations Component +
    + } + /> + + + , + ); + + await waitFor(() => { + expect(screen.getByText('User Login Page')).toBeInTheDocument(); + }); + }); + + test('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', [ + { + _id: '6537904485008f171cf29924', + __typename: 'Organization', + }, + ]); + + render( + + + Oops! The Page you requested was not found!
    } + /> + }> + + Organizations Component + + } + /> + + + , + ); + + expect( + screen.getByText(/Oops! The Page you requested was not found!/i), + ).toBeTruthy(); + }); +}); diff --git a/src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx b/src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx new file mode 100644 index 0000000000..f21047579d --- /dev/null +++ b/src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { Navigate, Outlet } from 'react-router-dom'; +import PageNotFound from 'screens/PageNotFound/PageNotFound'; +import useLocalStorage from 'utils/useLocalstorage'; + +const SecuredRouteForUser = (): JSX.Element => { + const { getItem } = useLocalStorage(); + const isLoggedIn = getItem('IsLoggedIn'); + const adminFor = getItem('AdminFor'); + return isLoggedIn === 'TRUE' ? ( + <>{adminFor == undefined ? : } + ) : ( + + ); +}; + +export default SecuredRouteForUser; diff --git a/src/components/UserPortal/StartPostModal/StartPostModal.module.css b/src/components/UserPortal/StartPostModal/StartPostModal.module.css new file mode 100644 index 0000000000..8b709f584d --- /dev/null +++ b/src/components/UserPortal/StartPostModal/StartPostModal.module.css @@ -0,0 +1,50 @@ +.userImage { + display: flex; + width: 50px; + height: 50px; + align-items: center; + justify-content: center; + overflow: hidden; + border-radius: 50%; + position: relative; + border: 2px solid #31bb6b; +} + +.userImage img { + position: absolute; + top: 0; + left: 0; + width: 100%; + scale: 1.5; +} + +.previewImage { + overflow: hidden; + display: flex; + justify-content: center; + align-items: center; + margin-bottom: 1rem; +} + +.previewImage img { + border-radius: 8px; +} + +.icons { + width: 25px; +} + +.icons svg { + stroke: #000; +} + +.icons.dark { + cursor: pointer; + border: none; + outline: none; + background-color: transparent; +} + +.icons.dark svg { + stroke: #000; +} diff --git a/src/components/UserPortal/StartPostModal/StartPostModal.test.tsx b/src/components/UserPortal/StartPostModal/StartPostModal.test.tsx new file mode 100644 index 0000000000..5a2e815af4 --- /dev/null +++ b/src/components/UserPortal/StartPostModal/StartPostModal.test.tsx @@ -0,0 +1,171 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import type { RenderResult } from '@testing-library/react'; +import { act, fireEvent, render, screen } from '@testing-library/react'; +import { I18nextProvider } from 'react-i18next'; +import userEvent from '@testing-library/user-event'; +import { CREATE_POST_MUTATION } from 'GraphQl/Mutations/mutations'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { toast } from 'react-toastify'; +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18nForTest from 'utils/i18nForTest'; +import StartPostModal from './StartPostModal'; + +jest.mock('react-toastify', () => ({ + toast: { + error: jest.fn(), + info: jest.fn(), + success: jest.fn(), + }, +})); + +const MOCKS = [ + { + request: { + query: CREATE_POST_MUTATION, + variables: { + title: '', + text: 'This is dummy text', + organizationId: '123', + file: '', + }, + result: { + data: { + createPost: { + _id: '453', + }, + }, + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); + +afterEach(() => { + localStorage.clear(); +}); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const renderStartPostModal = ( + visibility: boolean, + image: string | null, +): RenderResult => { + const cardProps = { + show: visibility, + onHide: jest.fn(), + fetchPosts: jest.fn(), + userData: { + user: { + __typename: 'User', + _id: '123', + image: image, + firstName: 'Glen', + lastName: 'dsza', + email: 'glen@dsza.com', + appLanguageCode: 'en', + pluginCreationAllowed: true, + createdAt: '2023-02-18T09:22:27.969Z', + adminFor: [], + createdOrganizations: [], + joinedOrganizations: [], + createdEvents: [], + registeredEvents: [], + eventAdmin: [], + membershipRequests: [], + organizationsBlockedBy: [], + }, + appUserProfile: { + __typename: 'AppUserProfile', + _id: '123', + isSuperAdmin: true, + adminFor: [], + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, + organizationId: '123', + img: '', + }; + + return render( + + + + + + + + + , + ); +}; + +describe('Testing StartPostModal Component: User Portal', () => { + afterAll(() => { + jest.clearAllMocks(); + }); + + test('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'); + renderStartPostModal(true, null); + await wait(); + + userEvent.click(screen.getByTestId('createPostBtn')); + expect(toastSpy).toBeCalledWith("Can't create a post with an empty body."); + }); + + test('On valid post submission Info toast should be shown', async () => { + renderStartPostModal(true, null); + await wait(); + + const randomPostInput = 'This is dummy text'; + userEvent.type(screen.getByTestId('postInput'), randomPostInput); + expect(screen.queryByText(randomPostInput)).toBeInTheDocument(); + + userEvent.click(screen.getByTestId('createPostBtn')); + + expect(toast.error).not.toBeCalledWith(); + expect(toast.info).toBeCalledWith('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 () => { + renderStartPostModal(true, null); + await wait(); + + const userImage = screen.getByTestId('userImage'); + expect(userImage).toHaveAttribute( + 'src', + '/src/assets/images/defaultImg.png', + ); + }); + + test('If user image is not null then user image should be shown', async () => { + renderStartPostModal(true, 'image.png'); + await wait(); + + const userImage = screen.getByTestId('userImage'); + expect(userImage).toHaveAttribute('src', 'image.png'); + }); +}); diff --git a/src/components/UserPortal/StartPostModal/StartPostModal.tsx b/src/components/UserPortal/StartPostModal/StartPostModal.tsx new file mode 100644 index 0000000000..91f3563147 --- /dev/null +++ b/src/components/UserPortal/StartPostModal/StartPostModal.tsx @@ -0,0 +1,140 @@ +import React, { useState } from 'react'; +import type { ChangeEvent } from 'react'; +import { Button, Form, Image, Modal } from 'react-bootstrap'; +import { toast } from 'react-toastify'; +import { useMutation } from '@apollo/client'; +import { useTranslation } from 'react-i18next'; + +import { errorHandler } from 'utils/errorHandler'; +import UserDefault from '../../../assets/images/defaultImg.png'; +import styles from './StartPostModal.module.css'; +import { CREATE_POST_MUTATION } from 'GraphQl/Mutations/mutations'; +import type { InterfaceQueryUserListItem } from 'utils/interfaces'; + +interface InterfaceStartPostModalProps { + show: boolean; + onHide: () => void; + fetchPosts: () => void; + userData: InterfaceQueryUserListItem | undefined; + organizationId: string; + img: string | null; +} + +const startPostModal = ({ + show, + onHide, + fetchPosts, + userData, + organizationId, + img, +}: InterfaceStartPostModalProps): JSX.Element => { + const { t } = useTranslation('translation', { keyPrefix: 'home' }); + const [postContent, setPostContent] = useState(''); + + const [createPost] = useMutation(CREATE_POST_MUTATION); + + const handlePostInput = (e: ChangeEvent): void => { + setPostContent(e.target.value); + }; + + const handleHide = (): void => { + setPostContent(''); + onHide(); + }; + + const handlePost = async (): Promise => { + try { + if (!postContent) { + throw new Error("Can't create a post with an empty body."); + } + toast.info('Processing your post. Please wait.'); + + const { data } = await createPost({ + variables: { + title: '', + text: postContent, + organizationId: organizationId, + file: img, + }, + }); + /* istanbul ignore next */ + if (data) { + toast.dismiss(); + toast.success(t('postNowVisibleInFeed')); + fetchPosts(); + handleHide(); + } + } catch (error: unknown) { + /* istanbul ignore next */ + errorHandler(t, error); + } + }; + + return ( + + + + + + + + {`${userData?.user?.firstName} ${userData?.user?.lastName}`} + + + +
    + + + {img && ( +
    + Post Image Preview +
    + )} +
    + + + +
    +
    + ); +}; + +export default startPostModal; diff --git a/src/components/UserPortal/UserNavbar/UserNavbar.module.css b/src/components/UserPortal/UserNavbar/UserNavbar.module.css new file mode 100644 index 0000000000..764a24ab93 --- /dev/null +++ b/src/components/UserPortal/UserNavbar/UserNavbar.module.css @@ -0,0 +1,26 @@ +.talawaImage { + width: 40px; + height: auto; + margin-top: -5px; + border: 2px solid white; + margin-right: 10px; + background-color: white; + border-radius: 10px; +} + +.boxShadow { + box-shadow: 4px 4px 8px 4px #c8c8c8; +} + +.colorWhite { + color: white; +} + +.colorPrimary { + background: #31bb6b; +} + +.link { + text-decoration: none !important; + color: inherit; +} diff --git a/src/components/UserPortal/UserNavbar/UserNavbar.test.tsx b/src/components/UserPortal/UserNavbar/UserNavbar.test.tsx new file mode 100644 index 0000000000..59e3585aa0 --- /dev/null +++ b/src/components/UserPortal/UserNavbar/UserNavbar.test.tsx @@ -0,0 +1,217 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { act, 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 i18nForTest from 'utils/i18nForTest'; +import cookies from 'js-cookie'; +import { StaticMockLink } from 'utils/StaticMockLink'; + +import UserNavbar from './UserNavbar'; +import userEvent from '@testing-library/user-event'; +import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const MOCKS = [ + { + request: { + query: REVOKE_REFRESH_TOKEN, + }, + result: {}, + }, +]; + +const link = new StaticMockLink(MOCKS, true); + +describe('Testing UserNavbar Component [User Portal]', () => { + afterEach(async () => { + await act(async () => { + await i18nForTest.changeLanguage('en'); + }); + }); + + test('Component should be rendered properly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + }); + + test('The language is switched to English', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('languageIcon')); + + userEvent.click(screen.getByTestId('changeLanguageBtn0')); + + await wait(); + + expect(cookies.get('i18next')).toBe('en'); + }); + + test('The language is switched to fr', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('languageIcon')); + + userEvent.click(screen.getByTestId('changeLanguageBtn1')); + + await wait(); + + expect(cookies.get('i18next')).toBe('fr'); + }); + + test('The language is switched to hi', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('languageIcon')); + + userEvent.click(screen.getByTestId('changeLanguageBtn2')); + + await wait(); + + expect(cookies.get('i18next')).toBe('hi'); + }); + + test('The language is switched to sp', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('languageIcon')); + + userEvent.click(screen.getByTestId('changeLanguageBtn3')); + + await wait(); + + expect(cookies.get('i18next')).toBe('sp'); + }); + + test('The language is switched to zh', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('languageIcon')); + + userEvent.click(screen.getByTestId('changeLanguageBtn4')); + + await wait(); + + expect(cookies.get('i18next')).toBe('zh'); + }); + + test('User can see and interact with the dropdown menu', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('logoutDropdown')); + expect(screen.getByText('Settings')).toBeInTheDocument(); + expect(screen.getByTestId('logoutBtn')).toBeInTheDocument(); + }); + + test('User can navigate to the "Settings" page', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('logoutDropdown')); + userEvent.click(screen.getByText('Settings')); + expect(window.location.pathname).toBe('/user/settings'); + }); +}); diff --git a/src/components/UserPortal/UserNavbar/UserNavbar.tsx b/src/components/UserPortal/UserNavbar/UserNavbar.tsx new file mode 100644 index 0000000000..f58c061440 --- /dev/null +++ b/src/components/UserPortal/UserNavbar/UserNavbar.tsx @@ -0,0 +1,120 @@ +import React from 'react'; +import styles from './UserNavbar.module.css'; +import TalawaImage from 'assets/images/talawa-logo-200x200.png'; +import { Container, Dropdown, Navbar } from 'react-bootstrap'; +import { languages } from 'utils/languages'; +import i18next from 'i18next'; +import cookies from 'js-cookie'; +import PermIdentityIcon from '@mui/icons-material/PermIdentity'; +import LanguageIcon from '@mui/icons-material/Language'; +import { useTranslation } from 'react-i18next'; +import { useMutation } from '@apollo/client'; +import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; +import { useNavigate } from 'react-router-dom'; +import useLocalStorage from 'utils/useLocalstorage'; + +function userNavbar(): JSX.Element { + const { getItem } = useLocalStorage(); + const navigate = useNavigate(); + + const { t } = useTranslation('translation', { + keyPrefix: 'userNavbar', + }); + const { t: tCommon } = useTranslation('common'); + + const [revokeRefreshToken] = useMutation(REVOKE_REFRESH_TOKEN); + + const [currentLanguageCode, setCurrentLanguageCode] = React.useState( + /* istanbul ignore next */ + cookies.get('i18next') || 'en', + ); + + const userName = getItem('name'); + + /* istanbul ignore next */ + const handleLogout = (): void => { + revokeRefreshToken(); + localStorage.clear(); + navigate('/'); + }; + + return ( + + + + Talawa Branding + {t('talawa')} + + + + + + + + + + {languages.map((language, index: number) => ( + => { + setCurrentLanguageCode(language.code); + await i18next.changeLanguage(language.code); + }} + disabled={currentLanguageCode === language.code} + data-testid={`changeLanguageBtn${index}`} + > + {' '} + {language.name} + + ))} + + + + + + + + + + {userName} + + navigate('/user/settings')} + className={styles.link} + > + {tCommon('settings')} + + + {tCommon('logout')} + + + + + + + ); +} + +export default userNavbar; diff --git a/src/components/UserPortal/UserSidebar/UserSidebar.module.css b/src/components/UserPortal/UserSidebar/UserSidebar.module.css new file mode 100644 index 0000000000..aafeaeff97 --- /dev/null +++ b/src/components/UserPortal/UserSidebar/UserSidebar.module.css @@ -0,0 +1,239 @@ +.leftDrawer { + width: calc(300px); + 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); + 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/UserPortal/UserSidebar/UserSidebar.test.tsx b/src/components/UserPortal/UserSidebar/UserSidebar.test.tsx new file mode 100644 index 0000000000..2984604951 --- /dev/null +++ b/src/components/UserPortal/UserSidebar/UserSidebar.test.tsx @@ -0,0 +1,417 @@ +import React from 'react'; +import type { RenderResult } from '@testing-library/react'; +import { act, fireEvent, render, screen } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider } from 'react-i18next'; + +import { + USER_DETAILS, + USER_JOINED_ORGANIZATIONS, +} from 'GraphQl/Queries/Queries'; +import { BrowserRouter } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import UserSidebar from './UserSidebar'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem } = useLocalStorage(); + +const resizeWindow = (width: number): void => { + window.innerWidth = width; + fireEvent(window, new Event('resize')); +}; + +const props = { + hideDrawer: true, + setHideDrawer: jest.fn(), +}; +const MOCKS = [ + { + request: { + query: USER_DETAILS, + variables: { + id: 'properId', + }, + }, + result: { + data: { + user: { + user: { + _id: 'properId', + image: null, + firstName: 'Noble', + lastName: 'Mittal', + email: 'noble@mittal.com', + createdAt: '2023-02-18T09:22:27.969Z', + joinedOrganizations: [], + membershipRequests: [], + registeredEvents: [], + gender: '', + birthDate: '2024-03-14', + educationGrade: '', + employmentStatus: '', + maritalStatus: '', + address: { + line1: '', + countryCode: '', + city: '', + state: '', + }, + phone: { + mobile: '', + }, + }, + appUserProfile: { + _id: 'properId', + adminFor: [], + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + isSuperAdmin: true, + pluginCreationAllowed: true, + appLanguageCode: 'en', + }, + }, + }, + }, + }, + { + request: { + query: USER_JOINED_ORGANIZATIONS, + variables: { + id: 'properId', + }, + }, + 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_DETAILS, + variables: { + id: 'imagePresent', + }, + }, + result: { + data: { + user: { + user: { + _id: '2', + image: 'adssda', + firstName: 'Noble', + lastName: 'Mittal', + email: 'noble@mittal.com', + createdAt: '2023-02-18T09:22:27.969Z', + joinedOrganizations: [], + membershipRequests: [], + registeredEvents: [], + gender: '', + birthDate: '2024-03-14', + educationGrade: '', + employmentStatus: '', + maritalStatus: '', + address: { + line1: '', + countryCode: '', + city: '', + state: '', + }, + phone: { + mobile: '', + }, + }, + appUserProfile: { + _id: '2', + adminFor: [], + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + isSuperAdmin: true, + pluginCreationAllowed: true, + appLanguageCode: 'en', + }, + }, + }, + }, + }, + { + request: { + query: USER_JOINED_ORGANIZATIONS, + variables: { + id: 'imagePresent', + }, + }, + result: { + data: { + users: [ + { + user: { + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + name: 'Any Organization', + image: 'dadsa', + 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_DETAILS, + variables: { + id: 'orgEmpty', + }, + }, + result: { + data: { + user: { + user: { + _id: 'orgEmpty', + image: null, + firstName: 'Noble', + lastName: 'Mittal', + email: 'noble@mittal.com', + createdAt: '2023-02-18T09:22:27.969Z', + joinedOrganizations: [], + membershipRequests: [], + registeredEvents: [], + gender: '', + birthDate: '2024-03-14', + educationGrade: '', + employmentStatus: '', + maritalStatus: '', + address: { + line1: '', + countryCode: '', + city: '', + state: '', + }, + phone: { + mobile: '', + }, + }, + appUserProfile: { + _id: 'orgEmpty', + adminFor: [], + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + isSuperAdmin: true, + pluginCreationAllowed: true, + appLanguageCode: 'en', + }, + }, + }, + }, + }, + { + request: { + query: USER_JOINED_ORGANIZATIONS, + variables: { + id: 'orgEmpty', + }, + }, + result: { + data: { + users: [ + { + user: { + joinedOrganizations: [], + }, + }, + ], + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const renderUserSidebar = ( + userId: string, + link: StaticMockLink, +): RenderResult => { + setItem('userId', userId); + return render( + + + + + + + + + , + ); +}; + +describe('Testing UserSidebar Component [User Portal]', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + test('Component should be rendered properly', async () => { + renderUserSidebar('properId', link); + await wait(); + }); + + test('Component should be rendered properly when userImage is present', async () => { + renderUserSidebar('imagePresent', link); + await wait(); + }); + + test('Component should be rendered properly when organizationImage is present', async () => { + renderUserSidebar('imagePresent', link); + await wait(); + }); + + test('Component should be rendered properly when joinedOrganizations list is empty', async () => { + renderUserSidebar('orgEmpty', link); + await wait(); + }); + + test('Testing Drawer when the screen size is less than or equal to 820px', () => { + resizeWindow(800); + render( + + + + + + + + + , + ); + 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.getAllByTestId(/orgsBtn/i); + + orgsBtn[0].click(); + expect( + orgsBtn[0].className.includes('text-white btn btn-success'), + ).toBeTruthy(); + settingsBtn.click(); + expect( + settingsBtn.className.includes('text-white btn btn-success'), + ).toBeTruthy(); + }); +}); diff --git a/src/components/UserPortal/UserSidebar/UserSidebar.tsx b/src/components/UserPortal/UserSidebar/UserSidebar.tsx new file mode 100644 index 0000000000..dc0c1e3622 --- /dev/null +++ b/src/components/UserPortal/UserSidebar/UserSidebar.tsx @@ -0,0 +1,119 @@ +import React from 'react'; +import Button from 'react-bootstrap/Button'; +import { useTranslation } from 'react-i18next'; +import { NavLink } from 'react-router-dom'; +import { ReactComponent as OrganizationsIcon } from 'assets/svgs/organizations.svg'; +import { ReactComponent as SettingsIcon } from 'assets/svgs/settings.svg'; +import { ReactComponent as ChatIcon } from 'assets/svgs/chat.svg'; +import { ReactComponent as TalawaLogo } from 'assets/svgs/talawa.svg'; +import styles from './UserSidebar.module.css'; + +export interface InterfaceUserSidebarProps { + hideDrawer: boolean | null; + setHideDrawer: React.Dispatch>; +} + +const userSidebar = ({ + hideDrawer, + setHideDrawer, +}: InterfaceUserSidebarProps): JSX.Element => { + const { t } = useTranslation('translation', { keyPrefix: 'userSidebarOrg' }); + const { t: tCommon } = useTranslation('common'); + + const handleLinkClick = (): void => { + if (window.innerWidth <= 820) { + setHideDrawer(true); + } + }; + + return ( + <> +
    + +

    {t('talawaUserPortal')}

    +
    + {tCommon('menu')} +
    +
    + + {({ isActive }) => ( + + )} + + + {({ isActive }) => ( + + )} + + + {({ isActive }) => ( + + )} + +
    +
    + + ); +}; + +export default userSidebar; diff --git a/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.module.css b/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.module.css new file mode 100644 index 0000000000..b300eb7e89 --- /dev/null +++ b/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.module.css @@ -0,0 +1,351 @@ +.leftDrawer { + width: calc(300px + 2rem); + min-height: 100%; + position: fixed; + top: 0; + bottom: 0; + z-index: 100; + display: flex; + flex-direction: column; + padding: 0.8rem 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 .brandingContainer { + display: flex; + justify-content: flex-start; + align-items: center; +} + +.leftDrawer .organizationContainer button { + position: relative; + margin: 0.7rem 0; + padding: 2.5rem 0.1rem; + border-radius: 16px; +} + +.leftDrawer .talawaLogo { + width: 50px; + height: 50px; + margin-right: 0.3rem; +} + +.leftDrawer .talawaText { + font-size: 18px; + font-weight: 500; +} + +.leftDrawer .titleHeader { + font-weight: 600; + margin: 0.6rem 0rem; +} + +.leftDrawer .optionList { + height: 100%; + overflow-y: auto; +} + +.leftDrawer .optionList button { + display: flex; + align-items: center; + width: 100%; + text-align: start; + margin-bottom: 0.8rem; + border-radius: 16px; + font-size: 16px; + padding: 0.6rem; + padding-left: 0.8rem; + outline: none; + border: none; +} + +.leftDrawer button .iconWrapper { + width: 36px; +} + +.leftDrawer .optionList .collapseBtn { + height: 48px; + border: none; +} + +.leftDrawer button .iconWrapperSm { + width: 36px; + display: flex; + justify-content: center; + align-items: center; +} + +.leftDrawer .organizationContainer .profileContainer { + background-color: #31bb6b33; + padding-right: 10px; +} + +.leftDrawer .profileContainer { + border: none; + width: 100%; + height: 52px; + border-radius: 16px; + display: flex; + align-items: center; + background-color: var(--bs-white); +} + +.leftDrawer .profileContainer:focus { + outline: none; +} + +.leftDrawer .imageContainer { + width: 68px; + margin-right: 8px; +} + +.leftDrawer .profileContainer img { + height: 52px; + width: 52px; + border-radius: 50%; +} + +.leftDrawer .profileContainer .profileText { + flex: 1; + text-align: start; + overflow: hidden; +} + +.leftDrawer .profileContainer .profileText .primaryText { + font-size: 1.1rem; + font-weight: 600; + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 2; /* number of lines to show */ + -webkit-box-orient: vertical; + word-wrap: break-word; + white-space: normal; +} + +.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-height: 900px) { + .leftDrawer { + width: calc(300px + 1rem); + } + .leftDrawer .talawaLogo { + width: 38px; + height: 38px; + margin-right: 0.4rem; + } + .leftDrawer .talawaText { + font-size: 1rem; + } + .leftDrawer .organizationContainer button { + margin: 0.6rem 0; + padding: 2.2rem 0.1rem; + } + .leftDrawer .optionList button { + margin-bottom: 0.05rem; + font-size: 16px; + padding-left: 0.8rem; + } + .leftDrawer .profileContainer .profileText .primaryText { + font-size: 1rem; + } + .leftDrawer .profileContainer .profileText .secondaryText { + font-size: 0.8rem; + } +} +@media (max-height: 650px) { + .leftDrawer { + padding: 0.5rem 0.8rem 0 0.8rem; + width: calc(250px); + } + .leftDrawer .talawaText { + font-size: 0.8rem; + } + .leftDrawer .organizationContainer button { + margin: 0.2rem 0; + padding: 1.6rem 0rem; + } + .leftDrawer .titleHeader { + font-size: 16px; + } + .leftDrawer .optionList button { + margin-bottom: 0.05rem; + font-size: 14px; + padding: 0.4rem; + padding-left: 0.8rem; + } + .leftDrawer .profileContainer .profileText .primaryText { + font-size: 0.8rem; + } + .leftDrawer .profileContainer .profileText .secondaryText { + font-size: 0.6rem; + } + .leftDrawer .imageContainer { + width: 40px; + margin-left: 5px; + margin-right: 12px; + } + .leftDrawer .imageContainer img { + width: 40px; + height: 100%; + } +} + +@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.2s ease-in-out; + } + + .activeDrawer { + display: flex; + z-index: 100; + animation: openDrawer 0.4s ease-in-out; + } + + .logout { + margin-bottom: 2.5rem; + } +} + +@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/UserPortal/UserSidebarOrg/UserSidebarOrg.test.tsx b/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.test.tsx new file mode 100644 index 0000000000..d9d70478b3 --- /dev/null +++ b/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.test.tsx @@ -0,0 +1,419 @@ +import React 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'; +import { Provider } from 'react-redux'; +import { MockedProvider } from '@apollo/react-testing'; +import { store } from 'state/store'; +import { ORGANIZATIONS_LIST } from 'GraphQl/Queries/Queries'; +import { act } from 'react-dom/test-utils'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem } = useLocalStorage(); + +const props: InterfaceUserSidebarOrgProps = { + orgId: '123', + targets: [ + { + name: 'Posts', + url: '/user/organization/123', + }, + { + name: 'People', + url: '/user/people/123', + }, + { + name: 'Events', + url: '/user/events/123', + }, + { + name: 'Donations', + url: '/user/donate/123', + }, + { + name: 'Settings', + url: '/user/settings', + }, + { + name: 'All Organizations', + url: '/user/organizations/', + }, + ], + hideDrawer: false, + setHideDrawer: jest.fn(), +}; + +const MOCKS = [ + { + request: { + query: REVOKE_REFRESH_TOKEN, + }, + result: { + data: { + revokeRefreshTokenForUser: true, + }, + }, + }, + { + request: { + query: ORGANIZATIONS_LIST, + variables: { id: '123' }, + }, + result: { + data: { + organizations: [ + { + _id: '123', + image: null, + creator: { + firstName: 'John', + lastName: 'Doe', + email: 'JohnDoe@example.com', + }, + name: 'Test Organization', + description: 'Testing this organization', + address: { + city: 'Delhi', + countryCode: 'IN', + dependentLocality: 'Some Dependent Locality', + line1: '123 Random Street', + line2: 'Apartment 456', + postalCode: '110001', + sortingCode: 'ABC-123', + state: 'Delhi', + }, + userRegistrationRequired: true, + visibleInSearch: true, + members: [ + { + _id: 'john123', + firstName: 'John', + lastName: 'Doe', + email: 'JohnDoe@example.com', + createdAt: '4567890234', + }, + { + _id: 'jane123', + firstName: 'Jane', + lastName: 'Doe', + email: 'JaneDoe@example.com', + createdAt: '4567890234', + }, + ], + admins: [ + { + _id: 'john123', + firstName: 'John', + lastName: 'Doe', + email: 'JohnDoe@example.com', + createdAt: '4567890234', + }, + ], + membershipRequests: [], + blockedUsers: [], + }, + ], + }, + }, + }, +]; + +const MOCKS_WITH_IMAGE = [ + { + request: { + query: ORGANIZATIONS_LIST, + variables: { id: '123' }, + }, + result: { + data: { + organizations: [ + { + _id: '123', + image: + 'https://api.dicebear.com/5.x/initials/svg?seed=Test%20Organization', + creator: { + firstName: 'John', + lastName: 'Doe', + email: 'JohnDoe@example.com', + }, + name: 'Test Organization', + description: 'Testing this organization', + address: { + city: 'Delhi', + countryCode: 'IN', + dependentLocality: 'Some Dependent Locality', + line1: '123 Random Street', + line2: 'Apartment 456', + postalCode: '110001', + sortingCode: 'ABC-123', + state: 'Delhi', + }, + userRegistrationRequired: true, + visibleInSearch: true, + members: [ + { + _id: 'john123', + firstName: 'John', + lastName: 'Doe', + email: 'JohnDoe@example.com', + createdAt: '4567890234', + }, + { + _id: 'jane123', + firstName: 'Jane', + lastName: 'Doe', + email: 'JaneDoe@example.com', + createdAt: '4567890234', + }, + ], + admins: [ + { + _id: 'john123', + firstName: 'John', + lastName: 'Doe', + email: 'JohnDoe@example.com', + createdAt: '4567890234', + }, + ], + membershipRequests: [], + blockedUsers: [], + }, + ], + }, + }, + }, +]; + +const MOCKS_EMPTY = [ + { + request: { + query: ORGANIZATIONS_LIST, + variables: { id: '123' }, + }, + result: { + data: { + organizations: [], + }, + }, + }, +]; + +const defaultScreens = [ + 'People', + 'Events', + 'Posts', + 'Donations', + 'All Organizations', +]; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }, +})); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const resizeWindow = (width: number): void => { + window.innerWidth = width; + fireEvent(window, new Event('resize')); +}; + +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(); +}); + +const link = new StaticMockLink(MOCKS, true); +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 () => { + setItem('UserImage', ''); + setItem('SuperAdmin', true); + setItem('FirstName', 'John'); + setItem('LastName', 'Doe'); + render( + + + + + + + + + , + ); + await wait(); + defaultScreens.map((screenName) => { + expect(screen.getByText(screenName)).toBeInTheDocument(); + }); + }); + + test('Testing Profile Page & Organization Detail Modal', async () => { + setItem('UserImage', ''); + setItem('SuperAdmin', true); + setItem('FirstName', 'John'); + setItem('LastName', 'Doe'); + render( + + + + + + + + + , + ); + await wait(); + expect(screen.getByTestId(/orgBtn/i)).toBeInTheDocument(); + }); + + test('Testing Menu Buttons', async () => { + setItem('UserImage', ''); + setItem('SuperAdmin', true); + setItem('FirstName', 'John'); + setItem('LastName', 'Doe'); + render( + + + + + + + + + , + ); + await wait(); + userEvent.click(screen.getByText('People')); + expect(global.window.location.pathname).toContain('/user/people/123'); + }); + + test('Testing when screen size is less than 820px', async () => { + setItem('SuperAdmin', true); + render( + + + + + + + + + , + ); + await wait(); + resizeWindow(800); + expect(screen.getByText(/People/i)).toBeInTheDocument(); + + const peopelBtn = screen.getByTestId(/People/i); + userEvent.click(peopelBtn); + await wait(); + expect(window.location.pathname).toContain('user/people/123'); + }); + + test('Testing when image is present for Organization', async () => { + setItem('UserImage', ''); + setItem('SuperAdmin', true); + setItem('FirstName', 'John'); + setItem('LastName', 'Doe'); + render( + + + + + + + + + , + ); + await wait(); + }); + + test('Testing when Organization does not exists', async () => { + setItem('UserImage', ''); + setItem('SuperAdmin', true); + setItem('FirstName', 'John'); + setItem('LastName', 'Doe'); + render( + + + + + + + + + , + ); + await wait(); + expect( + screen.getByText(/Error Occured while loading the Organization/i), + ).toBeInTheDocument(); + }); + + test('Testing Drawer when hideDrawer is null', () => { + setItem('UserImage', ''); + setItem('SuperAdmin', true); + setItem('FirstName', 'John'); + setItem('LastName', 'Doe'); + render( + + + + + + + + + , + ); + }); + + test('Testing Drawer when hideDrawer is true', () => { + setItem('UserImage', ''); + setItem('SuperAdmin', true); + setItem('FirstName', 'John'); + setItem('LastName', 'Doe'); + render( + + + + + + + + + , + ); + }); +}); diff --git a/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.tsx b/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.tsx new file mode 100644 index 0000000000..b56d5ea085 --- /dev/null +++ b/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.tsx @@ -0,0 +1,172 @@ +import { useQuery } from '@apollo/client'; +import { WarningAmberOutlined } from '@mui/icons-material'; +import { ORGANIZATIONS_LIST } from 'GraphQl/Queries/Queries'; +import CollapsibleDropdown from 'components/CollapsibleDropdown/CollapsibleDropdown'; +import IconComponent from 'components/IconComponent/IconComponent'; +import React, { useEffect, useState } from 'react'; +import Button from 'react-bootstrap/Button'; +import { useTranslation } from 'react-i18next'; +import { NavLink } from 'react-router-dom'; +import type { TargetsType } from 'state/reducers/routesReducer'; +import type { InterfaceQueryOrganizationsListObject } from 'utils/interfaces'; +import { ReactComponent as AngleRightIcon } from 'assets/svgs/angleRight.svg'; +import { ReactComponent as TalawaLogo } from 'assets/svgs/talawa.svg'; +import styles from './UserSidebarOrg.module.css'; +import Avatar from 'components/Avatar/Avatar'; + +export interface InterfaceUserSidebarOrgProps { + orgId: string; + targets: TargetsType[]; + hideDrawer: boolean | null; + setHideDrawer: React.Dispatch>; +} + +const UserSidebarOrg = ({ + targets, + orgId, + hideDrawer, + setHideDrawer, +}: InterfaceUserSidebarOrgProps): JSX.Element => { + const { t } = useTranslation('translation', { keyPrefix: 'userSidebarOrg' }); + const { t: tCommon } = useTranslation('common'); + const [showDropdown, setShowDropdown] = React.useState(false); + + const [organization, setOrganization] = + useState(); + const { + data, + loading, + }: { + data: + | { organizations: InterfaceQueryOrganizationsListObject[] } + | undefined; + loading: boolean; + } = useQuery(ORGANIZATIONS_LIST, { + variables: { id: orgId }, + }); + // Set organization data + useEffect(() => { + let isMounted = true; + if (data && isMounted) { + setOrganization(data?.organizations[0]); + console.log(targets, 'targets'); + } + return () => { + isMounted = false; + }; + }, [data]); + + const handleLinkClick = (): void => { + if (window.innerWidth <= 820) { + setHideDrawer(true); + } + }; + + return ( + <> +
    + {/* Branding Section */} +
    + + {t('talawaUserPortal')} +
    + + {/* Organization Section */} +
    + {loading ? ( + <> + + + ) : ( + + )} +
    + + {/* Options List */} +
    +
    + {tCommon('menu')} +
    + {targets.map(({ name, url }, index) => { + return url ? ( + + {({ isActive }) => ( + + )} + + ) : ( + + ); + })} +
    +
    + + ); +}; + +export default UserSidebarOrg; diff --git a/src/components/UserProfileSettings/DeleteUser.test.tsx b/src/components/UserProfileSettings/DeleteUser.test.tsx new file mode 100644 index 0000000000..34ab44fbe5 --- /dev/null +++ b/src/components/UserProfileSettings/DeleteUser.test.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { BrowserRouter } from 'react-router-dom'; +import { I18nextProvider } from 'react-i18next'; +import i18nForTest from 'utils/i18nForTest'; +import DeleteUser from './DeleteUser'; + +describe('Delete User component', () => { + test('renders delete user correctly', () => { + const { getByText, getAllByText } = render( + + + + + + + , + ); + + expect( + getByText( + 'By clicking on Delete User button your user will be permanently deleted along with its events, tags and all related data.', + ), + ).toBeInTheDocument(); + expect(getAllByText('Delete User')[0]).toBeInTheDocument(); + }); +}); diff --git a/src/components/UserProfileSettings/DeleteUser.tsx b/src/components/UserProfileSettings/DeleteUser.tsx new file mode 100644 index 0000000000..3a90542883 --- /dev/null +++ b/src/components/UserProfileSettings/DeleteUser.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { Button, Card } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; +import styles from './UserProfileSettings.module.css'; + +const DeleteUser: React.FC = () => { + const { t } = useTranslation('translation', { + keyPrefix: 'settings', + }); + return ( + <> + +
    +
    {t('deleteUser')}
    +
    + +

    {t('deleteUserMessage')}

    + +
    +
    + + ); +}; + +export default DeleteUser; diff --git a/src/components/UserProfileSettings/OtherSettings.test.tsx b/src/components/UserProfileSettings/OtherSettings.test.tsx new file mode 100644 index 0000000000..990a430931 --- /dev/null +++ b/src/components/UserProfileSettings/OtherSettings.test.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { BrowserRouter } from 'react-router-dom'; +import { I18nextProvider } from 'react-i18next'; +import i18nForTest from 'utils/i18nForTest'; +import OtherSettings from './OtherSettings'; + +describe('Delete User component', () => { + test('renders delete user correctly', () => { + const { getByText } = render( + + + + + + + , + ); + + expect(getByText('Other Settings')).toBeInTheDocument(); + expect(getByText('Change Language')).toBeInTheDocument(); + }); +}); diff --git a/src/components/UserProfileSettings/OtherSettings.tsx b/src/components/UserProfileSettings/OtherSettings.tsx new file mode 100644 index 0000000000..1e9723c2d6 --- /dev/null +++ b/src/components/UserProfileSettings/OtherSettings.tsx @@ -0,0 +1,26 @@ +import ChangeLanguageDropDown from 'components/ChangeLanguageDropdown/ChangeLanguageDropDown'; +import React from 'react'; +import { Card, Form } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; +import styles from './UserProfileSettings.module.css'; + +const OtherSettings: React.FC = () => { + const { t } = useTranslation('translation', { + keyPrefix: 'settings', + }); + return ( + +
    +
    {t('otherSettings')}
    +
    + + + {t('changeLanguage')} + + + +
    + ); +}; + +export default OtherSettings; diff --git a/src/components/UserProfileSettings/UserProfile.test.tsx b/src/components/UserProfileSettings/UserProfile.test.tsx new file mode 100644 index 0000000000..82caad5d81 --- /dev/null +++ b/src/components/UserProfileSettings/UserProfile.test.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import UserProfile from './UserProfile'; +import { MockedProvider } from '@apollo/react-testing'; +import { BrowserRouter } from 'react-router-dom'; +import { I18nextProvider } from 'react-i18next'; +import i18nForTest from 'utils/i18nForTest'; + +describe('UserProfile component', () => { + test('renders user profile details correctly', () => { + const userDetails = { + firstName: 'Christopher', + lastName: 'Doe', + createdAt: '2023-04-13T04:53:17.742+00:00', + email: 'john.doe@example.com', + image: 'profile-image-url', + }; + const { getByText, getByAltText } = render( + + + + + + + , + ); + + expect(getByText('Chris..')).toBeInTheDocument(); + expect(getByText('john..@example.com')).toBeInTheDocument(); + + const profileImage = getByAltText('profile picture'); + expect(profileImage).toBeInTheDocument(); + expect(profileImage).toHaveAttribute('src', 'profile-image-url'); + + expect(getByText('Joined 13 April 2023')).toBeInTheDocument(); + + expect(getByText('Copy Profile Link')).toBeInTheDocument(); + }); +}); diff --git a/src/components/UserProfileSettings/UserProfile.tsx b/src/components/UserProfileSettings/UserProfile.tsx new file mode 100644 index 0000000000..7af0939a75 --- /dev/null +++ b/src/components/UserProfileSettings/UserProfile.tsx @@ -0,0 +1,94 @@ +import Avatar from 'components/Avatar/Avatar'; +import React from 'react'; +import { Button, Card } from 'react-bootstrap'; +import CalendarMonthOutlinedIcon from '@mui/icons-material/CalendarMonthOutlined'; +import { useTranslation } from 'react-i18next'; +import styles from './UserProfileSettings.module.css'; +import { Tooltip as ReactTooltip } from 'react-tooltip'; + +interface InterfaceUserProfile { + firstName: string; + lastName: string; + createdAt: string; + email: string; + image: string; +} +const joinedDate = (param: string): string => { + const date = new Date(param); + if (date?.toDateString() === 'Invalid Date') { + return 'Unavailable'; + } + const day = date.getDate(); + const month = date.toLocaleString('default', { month: 'long' }); + const year = date.getFullYear(); + return `${day} ${month} ${year}`; +}; + +const UserProfile: React.FC = ({ + firstName, + lastName, + createdAt, + email, + image, +}): JSX.Element => { + const { t } = useTranslation('translation', { + keyPrefix: 'settings', + }); + const { t: tCommon } = useTranslation('common'); + return ( + <> + +
    +
    {t('profileDetails')}
    +
    + +
    +
    + {image && image !== 'null' ? ( + {`profile + ) : ( + + )} +
    +
    + + {firstName.length > 10 + ? firstName.slice(0, 5) + '..' + : firstName} + + + + {email.length > 10 + ? email.slice(0, 4) + '..' + email.slice(email.indexOf('@')) + : email} + + + + + + {tCommon('joined')} {joinedDate(createdAt)} + + +
    +
    +
    + +
    +
    +
    + + ); +}; + +export default UserProfile; diff --git a/src/components/UserProfileSettings/UserProfileSettings.module.css b/src/components/UserProfileSettings/UserProfileSettings.module.css new file mode 100644 index 0000000000..2c7cc76f57 --- /dev/null +++ b/src/components/UserProfileSettings/UserProfileSettings.module.css @@ -0,0 +1,77 @@ +.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.2rem; + font-weight: 600; +} + +.cardBody { + padding: 1.25rem 1rem 1.5rem 1rem; + display: flex; + flex-direction: column; +} + +.cardLabel { + font-weight: bold; + padding-bottom: 1px; + font-size: 14px; + color: #707070; + margin-bottom: 10px; +} + +.cardControl { + margin-bottom: 20px; +} + +.cardButton { + width: fit-content; +} + +.imgContianer { + margin: 0 2rem 0 0; +} + +.imgContianer img { + height: 120px; + width: 120px; + border-radius: 50%; +} + +.profileDetails { + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-evenly; + margin-left: 10%; +} + +@media screen and (max-width: 1280px) and (min-width: 992px) { + .imgContianer { + margin: 1rem auto; + } + .profileContainer { + flex-direction: column; + } +} + +@media screen and (max-width: 992px) { + .profileContainer { + align-items: center; + justify-content: center; + } +} + +@media screen and (max-width: 420px) { + .imgContianer { + margin: 1rem auto; + } + .profileContainer { + flex-direction: column; + } +} diff --git a/src/components/UsersTableItem/UserTableItem.test.tsx b/src/components/UsersTableItem/UserTableItem.test.tsx new file mode 100644 index 0000000000..bfa0a31c86 --- /dev/null +++ b/src/components/UsersTableItem/UserTableItem.test.tsx @@ -0,0 +1,1341 @@ +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 { toast } from 'react-toastify'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18nForTest from 'utils/i18nForTest'; +import type { InterfaceQueryUserListItem } from 'utils/interfaces'; +import { MOCKS, MOCKS2, MOCKS_UPDATE } from './UserTableItemMocks'; +import UsersTableItem from './UsersTableItem'; +import { BrowserRouter } from 'react-router-dom'; +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'; + +const { setItem } = useLocalStorage(); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} +const resetAndRefetchMock = jest.fn(); + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + warning: jest.fn(), + }, +})); + +Object.defineProperty(window, 'location', { + value: { + replace: jest.fn(), + }, + writable: true, +}); + +const mockNavgatePush = jest.fn(); + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useNavigate: () => mockNavgatePush, +})); + +beforeEach(() => { + setItem('SuperAdmin', true); + setItem('id', '123'); +}); + +afterEach(() => { + localStorage.clear(); + jest.clearAllMocks(); +}); + +describe('Testing User Table Item', () => { + console.error = jest.fn((message) => { + if (message.includes('validateDOMNesting')) { + return; + } + // Log other console errors + console.warn(message); + }); + test('Should render props and text elements test for the page component', async () => { + const props: { + user: InterfaceQueryUserListItem; + index: number; + loggedInUserId: string; + resetAndRefetch: () => void; + } = { + user: { + user: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '2023-09-29T15:39:36.355Z', + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'XYZ', + 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: '2023-01-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + }, + }, + { + _id: 'mno', + name: 'MNO', + 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: '2023-01-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + }, + }, + ], + 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: '2023-06-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + }, + }, + { + _id: 'def', + name: 'Joined Organization 2', + 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: '2023-07-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + }, + }, + ], + registeredEvents: [], + membershipRequests: [], + }, + appUserProfile: { + _id: '123', + isSuperAdmin: true, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + adminFor: [ + { + _id: 'abc', + }, + ], + }, + }, + index: 0, + loggedInUserId: '123', + resetAndRefetch: resetAndRefetchMock, + }; + + render( + + + + + + + , + ); + + await wait(); + expect(screen.getByText(/1/i)).toBeInTheDocument(); + expect(screen.getByText(/John Doe/i)).toBeInTheDocument(); + expect(screen.getByText(/john@example.com/i)).toBeInTheDocument(); + expect(screen.getByTestId(`showJoinedOrgsBtn${123}`)).toBeInTheDocument(); + expect( + screen.getByTestId(`showBlockedByOrgsBtn${123}`), + ).toBeInTheDocument(); + }); + + test('Should render elements correctly when JoinedOrgs and BlockedByOrgs are empty', async () => { + const props: { + user: InterfaceQueryUserListItem; + index: number; + loggedInUserId: string; + resetAndRefetch: () => void; + } = { + user: { + user: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '2023-09-29T15:39:36.355Z', + organizationsBlockedBy: [], + joinedOrganizations: [], + registeredEvents: [], + membershipRequests: [], + }, + appUserProfile: { + _id: '123', + isSuperAdmin: true, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + adminFor: [ + { + _id: 'abc', + }, + ], + }, + }, + index: 0, + loggedInUserId: '123', + resetAndRefetch: resetAndRefetchMock, + }; + render( + + + + + , + ); + + await wait(); + const showJoinedOrgsBtn = screen.getByTestId(`showJoinedOrgsBtn${123}`); // 123 is userId + const showBlockedByOrgsBtn = screen.getByTestId( + `showBlockedByOrgsBtn${123}`, + ); // 123 is userId + + // Open JoinedOrgs Modal -> Expect modal to contain text and no search box -> Close Modal + fireEvent.click(showJoinedOrgsBtn); + expect( + screen.queryByTestId(`searchByNameJoinedOrgs`), + ).not.toBeInTheDocument(); + expect( + screen.getByText(/John Doe has not joined any organization/i), + ).toBeInTheDocument(); + fireEvent.click(screen.getByTestId(`closeJoinedOrgsBtn${123}`)); + + // Open BlockedByOrgs Modal -> Expect modal to contain text and no search box -> Close Modal + fireEvent.click(showBlockedByOrgsBtn); + expect( + screen.queryByTestId(`searchByNameOrgsBlockedBy`), + ).not.toBeInTheDocument(); + expect( + screen.getByText(/John Doe is not blocked by any organization/i), + ).toBeInTheDocument(); + fireEvent.click(screen.getByTestId(`closeBlockedByOrgsBtn${123}`)); + }); + + test('Should render props and text elements test for the Joined Organizations Modal properly', async () => { + const props: { + user: InterfaceQueryUserListItem; + index: number; + loggedInUserId: string; + resetAndRefetch: () => void; + } = { + user: { + user: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '2023-09-29T15:39:36.355Z', + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'XYZ', + 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: '2023-01-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + }, + }, + { + _id: 'mno', + name: 'MNO', + 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: '2023-01-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + }, + }, + ], + 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: '2023-06-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + }, + }, + { + _id: 'def', + name: 'Joined Organization 2', + 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: '2023-07-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + }, + }, + ], + registeredEvents: [], + membershipRequests: [], + }, + appUserProfile: { + _id: '123', + isSuperAdmin: true, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + adminFor: [ + { + _id: 'abc', + }, + ], + }, + }, + index: 0, + loggedInUserId: '123', + resetAndRefetch: resetAndRefetchMock, + }; + + render( + + + + + , + ); + + await wait(); + const showJoinedOrgsBtn = screen.getByTestId(`showJoinedOrgsBtn${123}`); + expect(showJoinedOrgsBtn).toBeInTheDocument(); + fireEvent.click(showJoinedOrgsBtn); + expect(screen.getByTestId('modal-joined-org-123')).toBeInTheDocument(); + + // Close using escape key and reopen + fireEvent.keyDown(screen.getByTestId('modal-joined-org-123'), { + key: 'Escape', + code: 'Escape', + keyCode: 27, + charCode: 27, + }); + expect( + screen.queryByRole('dialog')?.className.includes('show'), + ).toBeFalsy(); + fireEvent.click(showJoinedOrgsBtn); + // Close using close button and reopen + fireEvent.click(screen.getByTestId(`closeJoinedOrgsBtn${123}`)); + expect( + screen.queryByRole('dialog')?.className.includes('show'), + ).toBeFalsy(); + + fireEvent.click(showJoinedOrgsBtn); + + // Expect the following to exist in modal + const inputBox = screen.getByTestId(`searchByNameJoinedOrgs`); + expect(inputBox).toBeInTheDocument(); + expect(screen.getByText(/Joined Organization 1/i)).toBeInTheDocument(); + expect(screen.getByText(/Joined Organization 2/i)).toBeInTheDocument(); + const elementsWithKingston = screen.getAllByText(/Kingston/i); + elementsWithKingston.forEach((element) => { + expect(element).toBeInTheDocument(); + }); + expect(screen.getByText(/29-06-2023/i)).toBeInTheDocument(); + expect(screen.getByText(/29-07-2023/i)).toBeInTheDocument(); + expect(screen.getByTestId('removeUserFromOrgBtnabc')).toBeInTheDocument(); + expect(screen.getByTestId('removeUserFromOrgBtndef')).toBeInTheDocument(); + + // Search for Joined Organization 1 + const searchBtn = screen.getByTestId(`searchBtnJoinedOrgs`); + fireEvent.keyUp(inputBox, { + target: { value: 'Joined Organization 1' }, + }); + fireEvent.click(searchBtn); + expect(screen.getByText(/Joined Organization 1/i)).toBeInTheDocument(); + expect( + screen.queryByText(/Joined Organization 2/i), + ).not.toBeInTheDocument(); + + // Search for an Organization which does not exist + fireEvent.keyUp(inputBox, { + key: 'Enter', + target: { value: 'Joined Organization 3' }, + }); + expect( + screen.getByText(`No results found for "Joined Organization 3"`), + ).toBeInTheDocument(); + + // Now clear the search box + fireEvent.keyUp(inputBox, { key: 'Enter', target: { value: '' } }); + fireEvent.keyUp(inputBox, { target: { value: '' } }); + fireEvent.click(searchBtn); + // Click on Creator Link + fireEvent.click(screen.getByTestId(`creatorabc`)); + expect(toast.success).toBeCalledWith('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'); + fireEvent.click(screen.getByTestId(`closeJoinedOrgsBtn${123}`)); + }); + + test('Should render props and text elements test for the Blocked By Organizations Modal properly', async () => { + const props: { + user: InterfaceQueryUserListItem; + index: number; + loggedInUserId: string; + resetAndRefetch: () => void; + } = { + user: { + user: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '2023-09-29T15:39:36.355Z', + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'XYZ', + 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: '2023-01-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + }, + }, + { + _id: 'mno', + name: 'MNO', + 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: '2023-03-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + }, + }, + ], + 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: '2023-06-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + }, + }, + { + _id: 'def', + name: 'Joined Organization 2', + 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: '2023-07-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + }, + }, + ], + registeredEvents: [], + membershipRequests: [], + }, + appUserProfile: { + _id: '123', + isSuperAdmin: true, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + adminFor: [ + { + _id: 'xyz', + }, + ], + }, + }, + index: 0, + loggedInUserId: '123', + resetAndRefetch: resetAndRefetchMock, + }; + + render( + + + + + + + , + ); + + await wait(); + const showBlockedByOrgsBtn = screen.getByTestId( + `showBlockedByOrgsBtn${123}`, + ); + expect(showBlockedByOrgsBtn).toBeInTheDocument(); + fireEvent.click(showBlockedByOrgsBtn); + expect(screen.getByTestId('modal-blocked-org-123')).toBeInTheDocument(); + + // Close using escape key and reopen + fireEvent.keyDown(screen.getByTestId('modal-blocked-org-123'), { + key: 'Escape', + code: 'Escape', + keyCode: 27, + charCode: 27, + }); + expect( + screen.queryByRole('dialog')?.className.includes('show'), + ).toBeFalsy(); + fireEvent.click(showBlockedByOrgsBtn); + // Close using close button and reopen + fireEvent.click(screen.getByTestId(`closeBlockedByOrgsBtn${123}`)); + expect( + screen.queryByRole('dialog')?.className.includes('show'), + ).toBeFalsy(); + + fireEvent.click(showBlockedByOrgsBtn); + + // Expect the following to exist in modal + + const inputBox = screen.getByTestId(`searchByNameOrgsBlockedBy`); + expect(inputBox).toBeInTheDocument(); + expect(screen.getByText(/XYZ/i)).toBeInTheDocument(); + expect(screen.getByText(/MNO/i)).toBeInTheDocument(); + const elementsWithKingston = screen.getAllByText(/Kingston/i); + elementsWithKingston.forEach((element) => { + expect(element).toBeInTheDocument(); + }); + expect(screen.getByText(/29-01-2023/i)).toBeInTheDocument(); + expect(screen.getByText(/29-03-2023/i)).toBeInTheDocument(); + expect(screen.getByTestId('removeUserFromOrgBtnxyz')).toBeInTheDocument(); + expect(screen.getByTestId('removeUserFromOrgBtnmno')).toBeInTheDocument(); + // Click on Creator Link + fireEvent.click(screen.getByTestId(`creatorxyz`)); + expect(toast.success).toBeCalledWith('Profile Page Coming Soon !'); + + // Search for Blocked Organization 1 + const searchBtn = screen.getByTestId(`searchBtnOrgsBlockedBy`); + fireEvent.keyUp(inputBox, { + target: { value: 'XYZ' }, + }); + fireEvent.click(searchBtn); + expect(screen.getByText(/XYZ/i)).toBeInTheDocument(); + expect(screen.queryByText(/MNO/i)).not.toBeInTheDocument(); + + // Search for an Organization which does not exist + fireEvent.keyUp(inputBox, { + key: 'Enter', + target: { value: 'Blocked Organization 3' }, + }); + expect( + screen.getByText(`No results found for "Blocked Organization 3"`), + ).toBeInTheDocument(); + + // Now clear the search box + fireEvent.keyUp(inputBox, { key: 'Enter', target: { value: '' } }); + fireEvent.keyUp(inputBox, { target: { value: '' } }); + fireEvent.click(searchBtn); + + // Click on Organization Link + fireEvent.click(screen.getByText(/XYZ/i)); + expect(window.location.replace).toBeCalledWith('/orgdash/xyz'); + expect(mockNavgatePush).toBeCalledWith('/orgdash/xyz'); + fireEvent.click(screen.getByTestId(`closeBlockedByOrgsBtn${123}`)); + }); + + test('Remove user from Organization should function properly in Organizations Joined Modal', async () => { + const props: { + user: InterfaceQueryUserListItem; + index: number; + loggedInUserId: string; + resetAndRefetch: () => void; + } = { + user: { + user: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '2023-09-29T15:39:36.355Z', + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'XYZ', + 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: '2023-01-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + }, + }, + { + _id: 'mno', + name: 'MNO', + 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: '2023-01-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + }, + }, + ], + 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: '2023-06-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + }, + }, + { + _id: 'def', + name: 'Joined Organization 2', + 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: '2023-07-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + }, + }, + ], + registeredEvents: [], + membershipRequests: [], + }, + appUserProfile: { + _id: '123', + isSuperAdmin: true, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + adminFor: [ + { + _id: 'abc', + }, + ], + }, + }, + index: 0, + loggedInUserId: '123', + resetAndRefetch: resetAndRefetchMock, + }; + + render( + + + + + + + , + ); + + await wait(); + const showJoinedOrgsBtn = screen.getByTestId(`showJoinedOrgsBtn${123}`); + expect(showJoinedOrgsBtn).toBeInTheDocument(); + fireEvent.click(showJoinedOrgsBtn); + expect(screen.getByTestId('modal-joined-org-123')).toBeInTheDocument(); + fireEvent.click(showJoinedOrgsBtn); + fireEvent.click(screen.getByTestId(`removeUserFromOrgBtn${'abc'}`)); + expect(screen.getByTestId('modal-remove-user-123')).toBeInTheDocument(); + + // Close using escape key and reopen + fireEvent.keyDown(screen.getByTestId('modal-joined-org-123'), { + key: 'Escape', + code: 'Escape', + keyCode: 27, + charCode: 27, + }); + expect( + screen + .queryAllByRole('dialog') + .some((el) => el.className.includes('show')), + ).toBeTruthy(); + fireEvent.click(showJoinedOrgsBtn); + // Close using close button and reopen + fireEvent.click(screen.getByTestId('closeRemoveUserModal123')); + expect( + screen + .queryAllByRole('dialog') + .some((el) => el.className.includes('show')), + ).toBeTruthy(); + + fireEvent.click(showJoinedOrgsBtn); + fireEvent.click(screen.getByTestId(`removeUserFromOrgBtn${'abc'}`)); + const confirmRemoveBtn = screen.getByTestId(`confirmRemoveUser123`); + expect(confirmRemoveBtn).toBeInTheDocument(); + + fireEvent.click(confirmRemoveBtn); + }); + + test('Remove user from Organization should function properly in Organizations Blocked by Modal', async () => { + const props: { + user: InterfaceQueryUserListItem; + index: number; + loggedInUserId: string; + resetAndRefetch: () => void; + } = { + user: { + user: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: 'https://api.dicebear.com/5.x/initials/svg?seed=John%20Doe', + email: 'john@example.com', + createdAt: '2022-09-29T15:39:36.355Z', + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'Blocked Organization 1', + image: + 'https://api.dicebear.com/5.x/initials/svg?seed=Blocked%20Organization%201', + 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: '2023-08-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: + 'https://api.dicebear.com/5.x/initials/svg?seed=John%20Doe', + email: 'john@example.com', + }, + }, + { + _id: 'mno', + name: 'Blocked Organization 2', + 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: '2023-09-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + }, + }, + ], + 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: '2023-08-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + }, + }, + { + _id: 'def', + name: 'Joined Organization 2', + 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: '2023-09-19T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + }, + }, + ], + registeredEvents: [], + membershipRequests: [], + }, + appUserProfile: { + _id: '123', + isSuperAdmin: true, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + adminFor: [ + { + _id: 'abc', + }, + { + _id: 'xyz', + }, + ], + }, + }, + index: 0, + loggedInUserId: '123', + resetAndRefetch: resetAndRefetchMock, + }; + + render( + + + + + + + , + ); + + await wait(); + const showBlockedByOrgsBtn = screen.getByTestId( + `showBlockedByOrgsBtn${123}`, + ); + expect(showBlockedByOrgsBtn).toBeInTheDocument(); + fireEvent.click(showBlockedByOrgsBtn); + expect(screen.getByTestId('modal-blocked-org-123')).toBeInTheDocument(); + fireEvent.click(showBlockedByOrgsBtn); + fireEvent.click(screen.getByTestId(`removeUserFromOrgBtn${'xyz'}`)); + expect(screen.getByTestId('modal-remove-user-123')).toBeInTheDocument(); + + // Close using escape key and reopen + fireEvent.keyDown(screen.getByTestId('modal-blocked-org-123'), { + key: 'Escape', + code: 'Escape', + keyCode: 27, + charCode: 27, + }); + expect( + screen + .queryAllByRole('dialog') + .some((el) => el.className.includes('show')), + ).toBeTruthy(); + fireEvent.click(showBlockedByOrgsBtn); + // Close using close button and reopen + fireEvent.click(screen.getByTestId('closeRemoveUserModal123')); + expect( + screen + .queryAllByRole('dialog') + .some((el) => el.className.includes('show')), + ).toBeTruthy(); + + fireEvent.click(showBlockedByOrgsBtn); + fireEvent.click(screen.getByTestId(`removeUserFromOrgBtn${'xyz'}`)); + const confirmRemoveBtn = screen.getByTestId(`confirmRemoveUser123`); + expect(confirmRemoveBtn).toBeInTheDocument(); + + fireEvent.click(confirmRemoveBtn); + }); + + test('handles errors in removeUser mutation', async () => { + const props: { + user: InterfaceQueryUserListItem; + index: number; + loggedInUserId: string; + resetAndRefetch: () => void; + } = { + user: { + user: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: 'https://api.dicebear.com/5.x/initials/svg?seed=John%20Doe', + email: '', + createdAt: '2022-09-29T15:39:36.355Z', + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'Blocked Organization 1', + image: + 'https://api.dicebear.com/5.x/initials/svg?seed=Blocked%20Organization%201', + 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: '2023-08-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: + 'https://api.dicebear.com/5.x/initials/svg?seed=John%20Doe', + email: '', + }, + }, + ], + 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: '2023-08-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: '', + }, + }, + ], + registeredEvents: [], + membershipRequests: [], + }, + appUserProfile: { + _id: '123', + isSuperAdmin: true, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + adminFor: [ + { + _id: 'abc', + }, + { + _id: 'xyz', + }, + ], + }, + }, + index: 0, + loggedInUserId: '123', + resetAndRefetch: resetAndRefetchMock, + }; + + const mocks = [ + { + request: { + query: REMOVE_MEMBER_MUTATION, + variables: { + userId: '123', + orgId: 'xyz', + }, + }, + result: { + errors: [ + { + message: 'User does not exist', + }, + ], + }, + }, + ]; + + render( + + + + + + + , + ); + + await wait(); + const showBlockedByOrgsBtn = screen.getByTestId( + `showBlockedByOrgsBtn${123}`, + ); + expect(showBlockedByOrgsBtn).toBeInTheDocument(); + fireEvent.click(showBlockedByOrgsBtn); + expect(screen.getByTestId('modal-blocked-org-123')).toBeInTheDocument(); + }); + + test('change role button should function properly', async () => { + const props: { + user: InterfaceQueryUserListItem; + index: number; + loggedInUserId: string; + resetAndRefetch: () => void; + } = { + user: { + user: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: 'https://api.dicebear.com/5.x/initials/svg?seed=John%20Doe', + email: '', + createdAt: '2022-09-29T15:39:36.355Z', + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'Blocked Organization 1', + image: + 'https://api.dicebear.com/5.x/initials/svg?seed=Blocked%20Organization%201', + 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: '2023-08-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: + 'https://api.dicebear.com/5.x/initials/svg?seed=John%20Doe', + email: '', + }, + }, + ], + 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: '2023-08-29T15:39:36.355Z', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: '', + }, + }, + ], + registeredEvents: [], + + membershipRequests: [], + }, + appUserProfile: { + _id: '123', + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + adminFor: [ + { + _id: 'abc', + }, + { + _id: 'xyz', + }, + ], + }, + }, + index: 0, + loggedInUserId: '123', + resetAndRefetch: resetAndRefetchMock, + }; + + render( + + + + + + + , + ); + + await wait(); + const showJoinedOrgs = screen.getByTestId(`showJoinedOrgsBtn${123}`); + expect(showJoinedOrgs).toBeInTheDocument(); + fireEvent.click(showJoinedOrgs); + const changeRoleBtn = screen.getByTestId( + `changeRoleInOrg${'abc'}`, + ) as HTMLSelectElement; + expect(changeRoleBtn).toBeInTheDocument(); + userEvent.selectOptions(changeRoleBtn, 'ADMIN'); + await wait(); + userEvent.selectOptions(changeRoleBtn, 'USER'); + await wait(); + expect(changeRoleBtn.value).toBe(`USER?abc`); + await wait(); + }); +}); diff --git a/src/components/UsersTableItem/UserTableItemMocks.ts b/src/components/UsersTableItem/UserTableItemMocks.ts new file mode 100644 index 0000000000..3162487f33 --- /dev/null +++ b/src/components/UsersTableItem/UserTableItemMocks.ts @@ -0,0 +1,86 @@ +import { + REMOVE_MEMBER_MUTATION, + UPDATE_USER_ROLE_IN_ORG_MUTATION, +} from 'GraphQl/Mutations/mutations'; + +const MOCKS = [ + { + request: { + query: REMOVE_MEMBER_MUTATION, + variables: { + userid: '123', + orgid: 'abc', + }, + }, + result: { + data: { + removeMember: { + _id: '123', + }, + }, + }, + }, + { + request: { + query: UPDATE_USER_ROLE_IN_ORG_MUTATION, + variables: { + userId: '123', + organizationId: 'abc', + role: 'USER', + }, + }, + result: { + data: { + updateUserRoleInOrganization: { + _id: '123', + }, + }, + }, + }, +]; + +const MOCKS2 = [ + { + request: { + query: REMOVE_MEMBER_MUTATION, + variables: { + userid: '123', + orgid: 'abc', + }, + }, + error: new Error('Failed to remove member'), + }, +]; + +const MOCKS_UPDATE = [ + { + request: { + query: UPDATE_USER_ROLE_IN_ORG_MUTATION, + variables: { + userId: '123', + organizationId: 'abc', + role: 'ADMIN', + }, + }, + error: new Error('Failed to update user role in organization'), + }, + { + request: { + query: UPDATE_USER_ROLE_IN_ORG_MUTATION, + variables: { + userId: '123', + organizationId: 'abc', + role: 'USER', + }, + }, + result: { + data: { + updateUserRoleInOrganization: { + _id: '123', + }, + }, + }, + }, +]; + +export { MOCKS, MOCKS2, MOCKS_UPDATE }; diff --git a/src/components/UsersTableItem/UsersTableItem.module.css b/src/components/UsersTableItem/UsersTableItem.module.css new file mode 100644 index 0000000000..d5fad679a7 --- /dev/null +++ b/src/components/UsersTableItem/UsersTableItem.module.css @@ -0,0 +1,26 @@ +.input { + position: relative; +} + +.notJoined { + height: 300px; + display: flex; + justify-content: center; + align-items: center; +} + +.modalTable img[alt='creator'] { + height: 24px; + width: 24px; + object-fit: contain; + border-radius: 12px; + margin-right: 0.4rem; +} + +.modalTable img[alt='orgImage'] { + height: 28px; + width: 28px; + object-fit: contain; + border-radius: 4px; + margin-right: 0.4rem; +} diff --git a/src/components/UsersTableItem/UsersTableItem.tsx b/src/components/UsersTableItem/UsersTableItem.tsx new file mode 100644 index 0000000000..9d6ec65187 --- /dev/null +++ b/src/components/UsersTableItem/UsersTableItem.tsx @@ -0,0 +1,591 @@ +import { useMutation } from '@apollo/client'; +import { Search } from '@mui/icons-material'; +import { + REMOVE_MEMBER_MUTATION, + UPDATE_USER_ROLE_IN_ORG_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import Avatar from 'components/Avatar/Avatar'; +import dayjs from 'dayjs'; +import React, { useState } from 'react'; +import { Button, Form, Modal, Row, Table } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; +import { useNavigate } from 'react-router-dom'; +import { toast } from 'react-toastify'; +import { errorHandler } from 'utils/errorHandler'; +import type { InterfaceQueryUserListItem } from 'utils/interfaces'; +import styles from './UsersTableItem.module.css'; +type Props = { + user: InterfaceQueryUserListItem; + index: number; + loggedInUserId: string; + resetAndRefetch: () => void; +}; +const UsersTableItem = (props: Props): JSX.Element => { + const { t } = useTranslation('translation', { keyPrefix: 'users' }); + const { t: tCommon } = useTranslation('common'); + const { user, index, resetAndRefetch } = props; + const [showJoinedOrganizations, setShowJoinedOrganizations] = useState(false); + const [showBlockedOrganizations, setShowBlockedOrganizations] = + useState(false); + const [showRemoveUserModal, setShowRemoveUserModal] = useState(false); + const [removeUserProps, setremoveUserProps] = useState<{ + orgName: string; + orgId: string; + setShowOnCancel: 'JOINED' | 'BLOCKED' | ''; + }>({ + orgName: '', + orgId: '', + setShowOnCancel: '', + }); + const [joinedOrgs, setJoinedOrgs] = useState(user.user.joinedOrganizations); + const [orgsBlockedBy, setOrgsBlockedBy] = useState( + user.user.organizationsBlockedBy, + ); + const [searchByNameJoinedOrgs, setSearchByNameJoinedOrgs] = useState(''); + const [searchByNameOrgsBlockedBy, setSearchByNameOrgsBlockedBy] = + useState(''); + const [removeUser] = useMutation(REMOVE_MEMBER_MUTATION); + const [updateUserInOrgType] = useMutation(UPDATE_USER_ROLE_IN_ORG_MUTATION); + const navigate = useNavigate(); + const confirmRemoveUser = async (): Promise => { + try { + const { data } = await removeUser({ + variables: { + userid: user.user._id, + orgid: removeUserProps.orgId, + }, + }); + if (data) { + toast.success(tCommon('removedSuccessfully', { item: 'User' })); + resetAndRefetch(); + } + } catch (error: unknown) { + errorHandler(t, error); + } + }; + const changeRoleInOrg = async ( + e: React.ChangeEvent, + ): Promise => { + const { value } = e.target; + const inputData = value.split('?'); + try { + const { data } = await updateUserInOrgType({ + variables: { + userId: user.user._id, + role: inputData[0], + organizationId: inputData[1], + }, + }); + if (data) { + toast.success(t('roleUpdated')); + resetAndRefetch(); + } + } catch (error: unknown) { + errorHandler(t, error); + } + }; + function goToOrg(_id: string): void { + const url = '/orgdash/' + _id; + window.location.replace(url); + navigate(url); + } + function handleCreator(): void { + toast.success('Profile Page Coming Soon !'); + } + const searchJoinedOrgs = (value: string): void => { + setSearchByNameJoinedOrgs(value); + if (value == '') { + setJoinedOrgs(user.user.joinedOrganizations); + } else { + const filteredOrgs = user.user.joinedOrganizations.filter((org) => + org.name.toLowerCase().includes(value.toLowerCase()), + ); + setJoinedOrgs(filteredOrgs); + } + }; + const searchOrgsBlockedBy = (value: string): void => { + setSearchByNameOrgsBlockedBy(value); + if (value == '') { + setOrgsBlockedBy(user.user.organizationsBlockedBy); + } else { + const filteredOrgs = user.user.organizationsBlockedBy.filter((org) => + org.name.toLowerCase().includes(value.toLowerCase()), + ); + setOrgsBlockedBy(filteredOrgs); + } + }; + const handleSearchJoinedOrgs = ( + e: React.KeyboardEvent, + ): void => { + if (e.key === 'Enter') { + const { value } = e.currentTarget; + searchJoinedOrgs(value); + } + }; + const handleSearchByOrgsBlockedBy = ( + e: React.KeyboardEvent, + ): void => { + if (e.key === 'Enter') { + const { value } = e.currentTarget; + searchOrgsBlockedBy(value); + } + }; + const handleSearchButtonClickJoinedOrgs = (): void => { + const inputValue = + (document.getElementById('orgname-joined-orgs') as HTMLInputElement) + ?.value || ''; + searchJoinedOrgs(inputValue); + }; + const handleSearchButtonClickOrgsBlockedBy = (): void => { + const inputValue = + (document.getElementById('orgname-blocked-by') as HTMLInputElement) + ?.value || ''; + searchOrgsBlockedBy(inputValue); + }; + function onHideRemoveUserModal(): void { + setShowRemoveUserModal(false); + if (removeUserProps.setShowOnCancel == 'JOINED') { + setShowJoinedOrganizations(true); + } else if (removeUserProps.setShowOnCancel == 'BLOCKED') { + setShowBlockedOrganizations(true); + } + } + const isSuperAdmin = user.appUserProfile.isSuperAdmin; + return ( + <> + + {index + 1} + {`${user.user.firstName} ${user.user.lastName}`} + {user.user.email} + + + + + + + + setShowJoinedOrganizations(false)} + > + + + {t('orgJoinedBy')} {`${user.user.firstName}`}{' '} + {`${user.user.lastName}`} ({user.user.joinedOrganizations.length}) + + + + {user.user.joinedOrganizations.length !== 0 && ( +
    + + +
    + )} + + {user.user.joinedOrganizations.length == 0 ? ( +
    +

    + {user.user.firstName} {user.user.lastName}{' '} + {t('hasNotJoinedAnyOrg')} +

    +
    + ) : joinedOrgs.length == 0 ? ( +
    +

    + {tCommon('noResultsFoundFor')} " + {searchByNameJoinedOrgs} + " +

    +
    + ) : ( + + + + + + + + + + + + + + {joinedOrgs.map((org) => { + let isAdmin = false; + user.appUserProfile.adminFor.map((item) => { + if (item._id == org._id) { + isAdmin = true; + } + }); + return ( + + + {org.address && } + + + + + + + ); + })} + +
    {tCommon('name')}{tCommon('address')}{tCommon('createdOn')}{tCommon('createdBy')}{tCommon('usersRole')}{tCommon('changeRole')}{tCommon('action')}
    + + {org.address.city}{dayjs(org.createdAt).format('DD-MM-YYYY')} + + + {isSuperAdmin + ? 'SUPERADMIN' + : isAdmin + ? 'ADMIN' + : 'USER'} + + + {isSuperAdmin ? ( + <> + + + + + ) : isAdmin ? ( + <> + + + + ) : ( + <> + + + + )} + + + +
    + )} +
    +
    + + + +
    + setShowBlockedOrganizations(false)} + data-testid={`modal-blocked-org-${user.user._id}`} + > + + + {t('orgThatBlocked')} {`${user.user.firstName}`}{' '} + {`${user.user.lastName}`} ({user.user.organizationsBlockedBy.length} + ) + + + + {user.user.organizationsBlockedBy.length !== 0 && ( +
    + + +
    + )} + + {user.user.organizationsBlockedBy.length == 0 ? ( +
    +

    + {user.user.firstName} {user.user.lastName}{' '} + {t('isNotBlockedByAnyOrg')} +

    +
    + ) : orgsBlockedBy.length == 0 ? ( +
    +

    {`${tCommon('noResultsFoundFor')} "${searchByNameOrgsBlockedBy}"`}

    +
    + ) : ( + + + + + + + + + + + + + + {orgsBlockedBy.map((org) => { + let isAdmin = false; + user.appUserProfile.adminFor.map((item) => { + if (item._id == org._id) { + isAdmin = true; + } + }); + return ( + + + {org.address && } + + + + + + + ); + })} + +
    {tCommon('name')}{tCommon('address')}{tCommon('createdOn')}{tCommon('createdBy')}{tCommon('usersRole')}{tCommon('changeRole')}{tCommon('action')}
    + + {org.address.city}{dayjs(org.createdAt).format('DD-MM-YYYY')} + + {isAdmin ? 'ADMIN' : 'USER'} + + {isSuperAdmin ? ( + <> + + + + + ) : isAdmin ? ( + <> + + + + ) : ( + <> + + + + )} + + + +
    + )} +
    +
    + + + +
    + onHideRemoveUserModal()} + > + + + {t('removeUserFrom', { org: removeUserProps.orgName })} + + + +

    + {t('removeConfirmation', { + name: `${user.user.firstName} ${user.user.lastName}`, + org: removeUserProps.orgName, + })} +

    +
    + + + + +
    + + ); +}; +export default UsersTableItem; diff --git a/src/components/Venues/VenueCard.tsx b/src/components/Venues/VenueCard.tsx new file mode 100644 index 0000000000..d4f6f97598 --- /dev/null +++ b/src/components/Venues/VenueCard.tsx @@ -0,0 +1,84 @@ +import React from 'react'; +import { Card, Button } from 'react-bootstrap'; +import defaultImg from 'assets/images/defaultImg.png'; +import { ReactComponent as PeopleIcon } from 'assets/svgs/people.svg'; +import styles from 'screens/OrganizationVenues/OrganizationVenues.module.css'; +import { useTranslation } from 'react-i18next'; +import type { InterfaceQueryVenueListItem } from 'utils/interfaces'; + +interface InterfaceVenueCardProps { + venueItem: InterfaceQueryVenueListItem; + index: number; + showEditVenueModal: (venueItem: InterfaceQueryVenueListItem) => void; + handleDelete: (venueId: string) => void; +} + +const VenueCard = ({ + venueItem, + index, + showEditVenueModal, + handleDelete, +}: InterfaceVenueCardProps): JSX.Element => { + const { t: tCommon } = useTranslation('common'); + return ( +
    +
    + + + + +
    + {venueItem.name.length > 25 + ? venueItem.name.slice(0, 25) + '...' + : venueItem.name} +
    + +
    + Capacity: {venueItem.capacity} + +
    +
    + + {venueItem.description && venueItem.description.length > 75 + ? venueItem.description.slice(0, 75) + '...' + : venueItem.description} + +
    +
    + + +
    +
    +
    +
    + ); +}; + +export default VenueCard; diff --git a/src/components/Venues/VenueModal.module.css b/src/components/Venues/VenueModal.module.css new file mode 100644 index 0000000000..e88b022187 --- /dev/null +++ b/src/components/Venues/VenueModal.module.css @@ -0,0 +1,53 @@ +.titlemodal { + color: #707070; + font-weight: 600; + font-size: 32px; + width: 65%; + margin-bottom: 0px; +} + +.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%; +} + +.preview { + display: flex; + position: relative; + width: 100%; + margin-top: 10px; + justify-content: center; +} +.preview img { + width: 400px; + height: auto; +} + +.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; +} diff --git a/src/components/Venues/VenueModal.test.tsx b/src/components/Venues/VenueModal.test.tsx new file mode 100644 index 0000000000..652816adaf --- /dev/null +++ b/src/components/Venues/VenueModal.test.tsx @@ -0,0 +1,287 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import type { RenderResult } from '@testing-library/react'; +import { act, 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'; +import VenueModal from './VenueModal'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; +import userEvent from '@testing-library/user-event'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { toast } from 'react-toastify'; +import { + CREATE_VENUE_MUTATION, + UPDATE_VENUE_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import type { ApolloLink } from '@apollo/client'; + +const MOCKS = [ + { + request: { + query: CREATE_VENUE_MUTATION, + variables: { + name: 'Test Venue', + description: 'Test Venue Desc', + capacity: 100, + organizationId: 'orgId', + file: '', + }, + }, + result: { + data: { + createVenue: { + _id: 'orgId', + }, + }, + }, + }, + { + request: { + query: UPDATE_VENUE_MUTATION, + variables: { + capacity: 200, + description: 'Updated description', + file: 'image1', + id: 'venue1', + name: 'Updated Venue', + organizationId: 'orgId', + }, + }, + result: { + data: { + editVenue: { + _id: 'venue1', + }, + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); + +const mockId = 'orgId'; +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: mockId }), +})); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + warning: jest.fn(), + error: jest.fn(), + }, +})); + +const props: InterfaceVenueModalProps[] = [ + { + show: true, + onHide: jest.fn(), + edit: false, + venueData: null, + refetchVenues: jest.fn(), + orgId: 'orgId', + }, + { + show: true, + onHide: jest.fn(), + edit: true, + venueData: { + _id: 'venue1', + name: 'Venue 1', + description: 'Updated description for venue 1', + image: 'image1', + capacity: '100', + }, + refetchVenues: jest.fn(), + orgId: 'orgId', + }, +]; + +const renderVenueModal = ( + props: InterfaceVenueModalProps, + link: ApolloLink, +): RenderResult => { + return render( + + + + + + + + + , + ); +}; + +describe('VenueModal', () => { + global.alert = jest.fn(); + + test('renders correctly when show is true', async () => { + renderVenueModal(props[0], link); + expect(screen.getByText('Venue Details')).toBeInTheDocument(); + }); + + test('does not render when show is false', () => { + const { container } = renderVenueModal({ ...props[0], show: false }, link); + expect(container.firstChild).toBeNull(); + }); + + test('populates form fields correctly in edit mode', () => { + renderVenueModal(props[1], link); + expect(screen.getByDisplayValue('Venue 1')).toBeInTheDocument(); + expect( + screen.getByDisplayValue('Updated description for venue 1'), + ).toBeInTheDocument(); + expect(screen.getByDisplayValue('100')).toBeInTheDocument(); + }); + + test('form fields are empty in create mode', () => { + renderVenueModal(props[0], link); + expect(screen.getByPlaceholderText('Enter Venue Name')).toHaveValue(''); + expect(screen.getByPlaceholderText('Enter Venue Description')).toHaveValue( + '', + ); + expect(screen.getByPlaceholderText('Enter Venue Capacity')).toHaveValue(''); + }); + + test('calls onHide when close button is clicked', () => { + renderVenueModal(props[0], link); + fireEvent.click(screen.getByTestId('createVenueModalCloseBtn')); + expect(props[0].onHide).toHaveBeenCalled(); + }); + + test('displays image preview and clear button when an image is selected', async () => { + renderVenueModal(props[0], link); + + const file = new File(['chad'], 'chad.png', { type: 'image/png' }); + const fileInput = screen.getByTestId('venueImgUrl'); + userEvent.upload(fileInput, file); + + await wait(); + + expect(screen.getByAltText('Venue Image Preview')).toBeInTheDocument(); + expect(screen.getByTestId('closeimage')).toBeInTheDocument(); + }); + + test('removes image preview when clear button is clicked', async () => { + renderVenueModal(props[0], link); + + const file = new File(['chad'], 'chad.png', { type: 'image/png' }); + const fileInput = screen.getByTestId('venueImgUrl'); + userEvent.upload(fileInput, file); + + await wait(); + + const form = screen.getByTestId('venueForm'); + form.addEventListener('submit', (e) => e.preventDefault()); + fireEvent.click(screen.getByTestId('closeimage')); + + expect( + screen.queryByAltText('Venue Image Preview'), + ).not.toBeInTheDocument(); + expect(screen.queryByTestId('closeimage')).not.toBeInTheDocument(); + }); + + test('shows error when venue name is empty', async () => { + renderVenueModal(props[0], link); + + const form = screen.getByTestId('venueForm'); + form.addEventListener('submit', (e) => e.preventDefault()); + + const submitButton = screen.getByTestId('createVenueBtn'); + fireEvent.click(submitButton); + + await wait(); + + expect(toast.error).toHaveBeenCalledWith('Venue title cannot be empty!'); + }); + + test('shows error when venue capacity is not a positive number', async () => { + renderVenueModal(props[0], link); + + const nameInput = screen.getByPlaceholderText('Enter Venue Name'); + fireEvent.change(nameInput, { target: { value: 'Test venue' } }); + + const capacityInput = screen.getByPlaceholderText('Enter Venue Capacity'); + fireEvent.change(capacityInput, { target: { value: '-1' } }); + + const form = screen.getByTestId('venueForm'); + form.addEventListener('submit', (e) => e.preventDefault()); + + const submitButton = screen.getByTestId('createVenueBtn'); + fireEvent.click(submitButton); + + await wait(); + + expect(toast.error).toHaveBeenCalledWith( + 'Capacity must be a positive number!', + ); + }); + + test('shows success toast when a new venue is created', async () => { + renderVenueModal(props[0], link); + + const nameInput = screen.getByPlaceholderText('Enter Venue Name'); + fireEvent.change(nameInput, { target: { value: 'Test Venue' } }); + const descriptionInput = screen.getByPlaceholderText( + 'Enter Venue Description', + ); + fireEvent.change(descriptionInput, { + target: { value: 'Test Venue Desc' }, + }); + + const capacityInput = screen.getByPlaceholderText('Enter Venue Capacity'); + fireEvent.change(capacityInput, { target: { value: 100 } }); + const form = screen.getByTestId('venueForm'); + form.addEventListener('submit', (e) => e.preventDefault()); + + const submitButton = screen.getByTestId('createVenueBtn'); + fireEvent.click(submitButton); + + await wait(); + + expect(toast.success).toHaveBeenCalledWith('Venue added Successfully'); + }); + + test('shows success toast when an existing venue is updated', async () => { + renderVenueModal(props[1], link); + + const nameInput = screen.getByDisplayValue('Venue 1'); + fireEvent.change(nameInput, { target: { value: 'Updated Venue' } }); + const descriptionInput = screen.getByDisplayValue( + 'Updated description for venue 1', + ); + fireEvent.change(descriptionInput, { + target: { value: 'Updated description' }, + }); + + const capacityInput = screen.getByDisplayValue('100'); + fireEvent.change(capacityInput, { target: { value: 200 } }); + const form = screen.getByTestId('venueForm'); + form.addEventListener('submit', (e) => e.preventDefault()); + + const submitButton = screen.getByTestId('updateVenueBtn'); + fireEvent.click(submitButton); + + await wait(); + + expect(toast.success).toHaveBeenCalledWith( + 'Venue details updated successfully', + ); + }); +}); diff --git a/src/components/Venues/VenueModal.tsx b/src/components/Venues/VenueModal.tsx new file mode 100644 index 0000000000..2ed8f826a5 --- /dev/null +++ b/src/components/Venues/VenueModal.tsx @@ -0,0 +1,242 @@ +import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { Button, Form, Modal } from 'react-bootstrap'; +import styles from './VenueModal.module.css'; +import { toast } from 'react-toastify'; +import { useTranslation } from 'react-i18next'; +import { useMutation } from '@apollo/client'; +import { + CREATE_VENUE_MUTATION, + UPDATE_VENUE_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import { errorHandler } from 'utils/errorHandler'; +import convertToBase64 from 'utils/convertToBase64'; +import type { InterfaceQueryVenueListItem } from 'utils/interfaces'; + +export interface InterfaceVenueModalProps { + show: boolean; + onHide: () => void; + refetchVenues: () => void; + orgId: string; + venueData?: InterfaceQueryVenueListItem | null; + edit: boolean; +} + +const VenueModal = ({ + show, + onHide, + refetchVenues, + orgId, + edit, + venueData, +}: InterfaceVenueModalProps): JSX.Element => { + const { t } = useTranslation('translation', { + keyPrefix: 'organizationVenues', + }); + const { t: tCommon } = useTranslation('common'); + + const [venueImage, setVenueImage] = useState(false); + const [formState, setFormState] = useState({ + name: venueData?.name || '', + description: venueData?.description || '', + capacity: venueData?.capacity || '', + imageURL: venueData?.image || '', + }); + + const fileInputRef = useRef(null); + + const [mutate, { loading }] = useMutation( + edit ? UPDATE_VENUE_MUTATION : CREATE_VENUE_MUTATION, + ); + + const handleSubmit = useCallback(async () => { + if (formState.name.trim().length === 0) { + toast.error(t('venueTitleError')); + return; + } + + const capacityNum = parseInt(formState.capacity); + if (isNaN(capacityNum) || capacityNum <= 0) { + toast.error(t('venueCapacityError')); + return; + } + try { + const { data } = await mutate({ + variables: { + capacity: capacityNum, + file: formState.imageURL, + description: formState.description, + name: formState.name, + organizationId: orgId, + ...(edit && { id: venueData?._id }), + }, + }); + /* istanbul ignore next */ + if (data) { + toast.success(edit ? t('venueUpdated') : t('venueAdded')); + refetchVenues(); + onHide(); + setFormState({ + name: '', + description: '', + capacity: '', + imageURL: '', + }); + setVenueImage(false); + } + } catch (error) { + /* istanbul ignore next */ + errorHandler(t, error); + } + }, [ + edit, + formState, + mutate, + onHide, + orgId, + refetchVenues, + t, + venueData?._id, + ]); + + const clearImageInput = useCallback(() => { + setFormState((prevState) => ({ ...prevState, imageURL: '' })); + setVenueImage(false); + /* istanbul ignore next */ + if (fileInputRef.current) { + fileInputRef.current.value = ''; + } + }, []); + + useEffect(() => { + setFormState({ + name: venueData?.name || '', + description: venueData?.description || '', + capacity: venueData?.capacity || '', + imageURL: venueData?.image || '', + }); + setVenueImage(venueData?.image ? true : false); + }, [venueData]); + + const { name, description, capacity, imageURL } = formState; + + return ( + + +

    {t('venueDetails')}

    + +
    + +
    + + { + setFormState({ + ...formState, + name: e.target.value, + }); + }} + /> + + { + setFormState({ + ...formState, + description: e.target.value, + }); + }} + /> + + { + setFormState({ + ...formState, + capacity: e.target.value, + }); + }} + /> + {t('image')} + , + ): Promise => { + setFormState((prevPostFormState) => ({ + ...prevPostFormState, + imageURL: '', + })); + setVenueImage(true); + const file = e.target.files?.[0]; + /* istanbul ignore next */ + if (file) { + setFormState({ + ...formState, + imageURL: await convertToBase64(file), + }); + } + }} + /> + {venueImage && ( +
    + Venue Image Preview + +
    + )} + + + +
    +
    + ); +}; + +export default VenueModal; diff --git a/src/components/plugins/DummyPlugin/DummyPlugin.module.css b/src/components/plugins/DummyPlugin/DummyPlugin.module.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/components/plugins/DummyPlugin/DummyPlugin.test.jsx b/src/components/plugins/DummyPlugin/DummyPlugin.test.jsx new file mode 100644 index 0000000000..ae792966fe --- /dev/null +++ b/src/components/plugins/DummyPlugin/DummyPlugin.test.jsx @@ -0,0 +1,29 @@ +import { MockedProvider } from '@apollo/react-testing'; +import { render } from '@testing-library/react'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { I18nextProvider } from 'react-i18next'; +import React from 'react'; + +import { store } from 'state/store'; +import DummyPlugin from './DummyPlugin'; +import i18nForTest from 'utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; +const link = new StaticMockLink([], true); +describe('Testing dummy plugin', () => { + test('should render props and text elements test for the page component', () => { + const { getByText } = render( + + + + + + + + + + ); + + expect(getByText(/Welcome to the Dummy Plugin!/i)).toBeInTheDocument(); + }); +}); diff --git a/src/components/plugins/DummyPlugin/DummyPlugin.tsx b/src/components/plugins/DummyPlugin/DummyPlugin.tsx new file mode 100644 index 0000000000..8fd2388784 --- /dev/null +++ b/src/components/plugins/DummyPlugin/DummyPlugin.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import AddOn from 'components/AddOn/AddOn'; + +// Validate Extras +function dummyPlugin(): JSX.Element { + return ( + +
    Welcome to the Dummy Plugin!
    +
    + ); +} + +dummyPlugin.defaultProps = {}; + +dummyPlugin.propTypes = {}; + +export default dummyPlugin; diff --git a/src/components/plugins/DummyPlugin2/DummyPlugin2.module.css b/src/components/plugins/DummyPlugin2/DummyPlugin2.module.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/components/plugins/DummyPlugin2/DummyPlugin2.test.jsx b/src/components/plugins/DummyPlugin2/DummyPlugin2.test.jsx new file mode 100644 index 0000000000..bcec97367c --- /dev/null +++ b/src/components/plugins/DummyPlugin2/DummyPlugin2.test.jsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { store } from 'state/store'; +import DummyPlugin2 from './DummyPlugin2'; + +describe('Testing dummy plugin 2', () => { + test('should render props and text elements test for the page component', () => { + render( + + + + + + ); + }); +}); diff --git a/src/components/plugins/DummyPlugin2/DummyPlugin2.tsx b/src/components/plugins/DummyPlugin2/DummyPlugin2.tsx new file mode 100644 index 0000000000..2e96213e23 --- /dev/null +++ b/src/components/plugins/DummyPlugin2/DummyPlugin2.tsx @@ -0,0 +1,12 @@ +import React from 'react'; + +// Validate Extras +function dummyPlugin2(): JSX.Element { + return
    ; +} + +dummyPlugin2.defaultProps = {}; + +dummyPlugin2.propTypes = {}; + +export default dummyPlugin2; diff --git a/src/components/plugins/index.ts b/src/components/plugins/index.ts new file mode 100644 index 0000000000..db688e0da2 --- /dev/null +++ b/src/components/plugins/index.ts @@ -0,0 +1,4 @@ +import DummyPlugin from './DummyPlugin/DummyPlugin'; +import DummyPlugin2 from './DummyPlugin2/DummyPlugin2'; + +export { DummyPlugin, DummyPlugin2 }; diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 0000000000..bddae030fa --- /dev/null +++ b/src/constants.ts @@ -0,0 +1,53 @@ +import { + FacebookLogo, + LinkedInLogo, + GithubLogo, + InstagramLogo, + SlackLogo, + TwitterLogo, + YoutubeLogo, + RedditLogo, +} from 'assets/svgs/social-icons'; + +export const socialMediaLinks = [ + { + tag: 'facebook', + href: 'https://www.facebook.com/palisadoesproject', + logo: FacebookLogo, + }, + { + tag: 'twitter', + href: 'https://twitter.com/palisadoesorg?lang=en', + logo: TwitterLogo, + }, + { + tag: 'linkedIn', + href: 'https://www.linkedin.com/company/palisadoes/', + logo: LinkedInLogo, + }, + { + tag: 'gitHub', + href: 'https://github.com/PalisadoesFoundation', + logo: GithubLogo, + }, + { + tag: 'youTube', + href: 'https://www.youtube.com/@PalisadoesOrganization', + logo: YoutubeLogo, + }, + { + tag: 'slack', + href: 'https://www.palisadoes.org/slack', + logo: SlackLogo, + }, + { + tag: 'instagram', + href: 'https://www.instagram.com/palisadoes/', + logo: InstagramLogo, + }, + { + tag: 'reddit', + href: '', + logo: RedditLogo, + }, +]; diff --git a/src/index.css b/src/index.css deleted file mode 100644 index ec2585e8c0..0000000000 --- a/src/index.css +++ /dev/null @@ -1,13 +0,0 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; -} diff --git a/src/index.tsx b/src/index.tsx index 15d9bd34d8..44cb0578b6 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,14 +1,150 @@ -import React from 'react'; +import React, { Suspense } from 'react'; import ReactDOM from 'react-dom'; -import './index.css'; +import { BrowserRouter } from 'react-router-dom'; +import type { NormalizedCacheObject } from '@apollo/client'; +import { + ApolloClient, + ApolloProvider, + InMemoryCache, + HttpLink, + split, +} from '@apollo/client'; +import { getMainDefinition } from '@apollo/client/utilities'; +import { GraphQLWsLink } from '@apollo/client/link/subscriptions'; +import { createClient } from 'graphql-ws'; +import { onError } from '@apollo/link-error'; +import './assets/css/app.css'; +import 'bootstrap/dist/js/bootstrap.min.js'; +import 'react-datepicker/dist/react-datepicker.css'; +import 'flag-icons/css/flag-icons.min.css'; +import { Provider } from 'react-redux'; +import { ToastContainer, toast } from 'react-toastify'; +import 'react-toastify/dist/ReactToastify.css'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; + import App from './App'; -import reportWebVitals from './reportWebVitals'; +import { store } from './state/store'; +import { + BACKEND_URL, + REACT_APP_BACKEND_WEBSOCKET_URL, +} from 'Constant/constant'; +import { refreshToken } from 'utils/getRefreshToken'; +import { ThemeProvider, createTheme } from '@mui/material'; +import { ApolloLink } from '@apollo/client/core'; +import { setContext } from '@apollo/client/link/context'; +import '../src/assets/css/scrollStyles.css'; -ReactDOM.render( - - - , - document.getElementById('root') +const theme = createTheme({ + palette: { + primary: { + main: '#31bb6b', + }, + }, +}); +import useLocalStorage from 'utils/useLocalstorage'; +import i18n from './utils/i18n'; + +const { getItem } = useLocalStorage(); +const authLink = setContext((_, { headers }) => { + const lng = i18n.language; + return { + headers: { + ...headers, + authorization: 'Bearer ' + getItem('token') || '', + 'Accept-Language': lng, + }, + }; +}); + +const errorLink = onError( + ({ graphQLErrors, networkError, operation, forward }) => { + if (graphQLErrors) { + graphQLErrors.map(({ message }) => { + if (message === 'User is not authenticated') { + refreshToken().then((success) => { + if (success) { + const oldHeaders = operation.getContext().headers; + operation.setContext({ + headers: { + ...oldHeaders, + authorization: 'Bearer ' + getItem('token'), + }, + }); + return forward(operation); + } else { + localStorage.clear(); + } + }); + } + }); + } else if (networkError) { + console.log(`[Network error]: ${networkError}`); + toast.error( + 'API server unavailable. Check your connection or try again later', + { + toastId: 'apiServer', + }, + ); + } + }, +); + +const httpLink = new HttpLink({ + uri: BACKEND_URL, +}); + +// if didnt work use /subscriptions +const wsLink = new GraphQLWsLink( + createClient({ + url: REACT_APP_BACKEND_WEBSOCKET_URL, + }), ); -reportWebVitals(); +// const wsLink = new GraphQLWsLink( +// createClient({ +// url: 'ws://localhost:4000/subscriptions', +// }), +// ); +// The split function takes three parameters: +// +// * A function that's called for each operation to execute +// * The Link to use for an operation if the function returns a "truthy" value +// * The Link to use for an operation if the function returns a "falsy" value +const splitLink = split( + ({ query }) => { + const definition = getMainDefinition(query); + return ( + definition.kind === 'OperationDefinition' && + definition.operation === 'subscription' + ); + }, + wsLink, + httpLink, +); + +const combinedLink = ApolloLink.from([errorLink, authLink, splitLink]); + +const client: ApolloClient = new ApolloClient({ + cache: new InMemoryCache(), + link: combinedLink, +}); +const fallbackLoader =
    ; + +ReactDOM.render( + + + + + + + + + + + + + + , + document.getElementById('root'), +); diff --git a/src/reportWebVitals.ts b/src/reportWebVitals.ts index eb4be08f20..f49db29f28 100644 --- a/src/reportWebVitals.ts +++ b/src/reportWebVitals.ts @@ -1,13 +1,13 @@ -import { ReportHandler } from 'web-vitals'; +import { promises } from 'dns'; +import type { MetricType } from 'web-vitals'; -const reportWebVitals = (onPerfEntry?: ReportHandler): void => { +const reportWebVitals = (onPerfEntry?: (metric: MetricType) => void): void => { if (onPerfEntry && onPerfEntry instanceof Function) { - import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { - getCLS(onPerfEntry); - getFID(onPerfEntry); - getFCP(onPerfEntry); - getLCP(onPerfEntry); - getTTFB(onPerfEntry); + import('web-vitals').then(({ onCLS, onFCP, onLCP, onTTFB }) => { + onCLS(onPerfEntry); + onFCP(onPerfEntry); + onLCP(onPerfEntry); + onTTFB(onPerfEntry); }); } }; diff --git a/src/screens/BlockUser/BlockUser.module.css b/src/screens/BlockUser/BlockUser.module.css new file mode 100644 index 0000000000..ed93446206 --- /dev/null +++ b/src/screens/BlockUser/BlockUser.module.css @@ -0,0 +1,102 @@ +.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; +} + +.largeBtnsWrapper { + display: flex; +} + +.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; + } + + .largeBtnsWrapper { + flex-direction: column; + } + + .btnsContainer .btnsBlock div { + flex: 1; + } + + .btnsContainer .btnsBlock button { + margin-bottom: 1rem; + margin-right: 0; + width: 100%; + } +} diff --git a/src/screens/BlockUser/BlockUser.test.tsx b/src/screens/BlockUser/BlockUser.test.tsx new file mode 100644 index 0000000000..bb490fbe3f --- /dev/null +++ b/src/screens/BlockUser/BlockUser.test.tsx @@ -0,0 +1,668 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { act, render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { + BLOCK_USER_MUTATION, + UNBLOCK_USER_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import { + BLOCK_PAGE_MEMBER_LIST, + ORGANIZATIONS_LIST, +} from 'GraphQl/Queries/Queries'; +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 { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18nForTest from 'utils/i18nForTest'; + +import BlockUser from './BlockUser'; + +let userQueryCalled = false; + +const USER_BLOCKED = { + _id: '123', + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@gmail.com', + organizationsBlockedBy: [ + { + _id: 'orgid', + }, + ], +}; + +const USER_UNBLOCKED = { + _id: '456', + firstName: 'Sam', + lastName: 'Smith', + email: 'samsmith@gmail.com', + organizationsBlockedBy: [], +}; + +const DATA_INITIAL = { + data: { + organizationsMemberConnection: { + edges: [USER_BLOCKED, USER_UNBLOCKED], + }, + }, +}; + +const DATA_AFTER_MUTATION = { + data: { + organizationsMemberConnection: { + edges: [ + { + _id: '123', + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@gmail.com', + organizationsBlockedBy: [], + }, + { + _id: '456', + firstName: 'Sam', + lastName: 'Smith', + email: 'samsmith@gmail.com', + organizationsBlockedBy: [ + { + _id: 'orgid', + }, + ], + }, + ], + }, + }, +}; + +const MOCKS = [ + { + request: { + query: ORGANIZATIONS_LIST, + variables: { + id: 'orgid', + }, + }, + result: { + data: { + organizations: [ + { + _id: 'orgid', + image: '', + creator: { + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + name: 'name', + description: 'description', + location: 'location', + members: { + _id: 'id', + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + admins: { + _id: 'id', + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + membershipRequests: { + _id: 'id', + user: { + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + }, + blockedUsers: { + _id: 'id', + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + }, + ], + }, + }, + }, + + { + request: { + query: BLOCK_USER_MUTATION, + variables: { + userId: '456', + orgId: 'orgid', + }, + }, + result: { + data: { + blockUser: { + _id: '456', + }, + }, + }, + }, + + { + request: { + query: UNBLOCK_USER_MUTATION, + variables: { + userId: '123', + orgId: 'orgid', + }, + }, + result: { + data: { + unblockUser: { + _id: '123', + }, + }, + }, + }, + + { + request: { + query: BLOCK_PAGE_MEMBER_LIST, + variables: { + firstName_contains: '', + lastName_contains: '', + orgId: 'orgid', + }, + }, + result: DATA_INITIAL, + newData: (): typeof DATA_AFTER_MUTATION | typeof DATA_INITIAL => { + if (userQueryCalled) { + return DATA_AFTER_MUTATION; + } else { + userQueryCalled = true; + + return DATA_INITIAL; + } + }, + }, + + { + request: { + query: BLOCK_PAGE_MEMBER_LIST, + variables: { + firstName_contains: 'john', + lastName_contains: '', + orgId: 'orgid', + }, + }, + result: { + data: { + organizationsMemberConnection: { + edges: [USER_BLOCKED], + }, + }, + }, + }, + + { + request: { + query: BLOCK_PAGE_MEMBER_LIST, + variables: { + firstName_contains: '', + lastName_contains: 'doe', + orgId: 'orgid', + }, + }, + result: { + data: { + organizationsMemberConnection: { + edges: [USER_BLOCKED], + }, + }, + }, + }, + + { + request: { + query: BLOCK_PAGE_MEMBER_LIST, + variables: { + firstName_contains: 'Peter', + lastName_contains: '', + orgId: 'orgid', + }, + }, + result: { + data: { + organizationsMemberConnection: { + edges: [], + }, + }, + }, + }, +]; +const MOCKS_EMPTY = [ + { + request: { + query: ORGANIZATIONS_LIST, + variables: { + id: 'orgid', + }, + }, + result: { + data: { + organizations: [ + { + _id: 'orgid', + image: '', + creator: { + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + name: 'name', + description: 'description', + location: 'location', + members: { + _id: 'id', + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + admins: { + _id: 'id', + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + membershipRequests: { + _id: 'id', + user: { + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + }, + blockedUsers: { + _id: 'id', + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + }, + ], + }, + }, + }, + + { + request: { + query: BLOCK_PAGE_MEMBER_LIST, + variables: { + firstName_contains: 'Peter', + lastName_contains: '', + orgId: 'orgid', + }, + }, + result: { + data: { + organizationsMemberConnection: { + edges: [], + }, + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(MOCKS_EMPTY, true); + +async function wait(ms = 500): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: 'orgid' }), +})); + +describe('Testing Block/Unblock user screen', () => { + beforeEach(() => { + userQueryCalled = false; + }); + + test('Components should be rendered properly', async () => { + window.location.assign('/blockuser/orgid'); + + render( + + + + + + + + + , + ); + + await wait(); + + expect(screen.getByText('Search By First Name')).toBeInTheDocument(); + + expect(window.location).toBeAt('/blockuser/orgid'); + }); + + test('Testing block user functionality', async () => { + window.location.assign('/blockuser/orgid'); + + render( + + + + + + + + + , + ); + + await act(async () => { + userEvent.click(screen.getByTestId('userFilter')); + }); + userEvent.click(screen.getByTestId('showMembers')); + await wait(); + + expect(screen.getByTestId('unBlockUser123')).toBeInTheDocument(); + expect(screen.getByTestId('blockUser456')).toBeInTheDocument(); + + userEvent.click(screen.getByTestId('unBlockUser123')); + await wait(); + + expect(screen.getByTestId('blockUser123')).toBeInTheDocument(); + expect(screen.getByTestId('unBlockUser456')).toBeInTheDocument(); + + expect(window.location).toBeAt('/blockuser/orgid'); + }); + + test('Testing unblock user functionality', async () => { + window.location.assign('/blockuser/orgid'); + + render( + + + + + + + + + , + ); + await act(async () => { + userEvent.click(screen.getByTestId('userFilter')); + }); + userEvent.click(screen.getByTestId('showMembers')); + + await wait(); + + expect(screen.getByTestId('unBlockUser123')).toBeInTheDocument(); + expect(screen.getByTestId('blockUser456')).toBeInTheDocument(); + + userEvent.click(screen.getByTestId('blockUser456')); + await wait(); + + expect(screen.getByTestId('blockUser123')).toBeInTheDocument(); + expect(screen.getByTestId('unBlockUser456')).toBeInTheDocument(); + + expect(window.location).toBeAt('/blockuser/orgid'); + }); + + test('Testing First Name Filter', async () => { + window.location.assign('/blockuser/orgid'); + + render( + + + + + + + + + , + ); + await act(async () => { + userEvent.click(screen.getByTestId('userFilter')); + }); + userEvent.click(screen.getByTestId('showMembers')); + + await wait(); + + expect(screen.getByText('John Doe')).toBeInTheDocument(); + expect(screen.getByText('Sam Smith')).toBeInTheDocument(); + + // Open Dropdown + await act(async () => { + userEvent.click(screen.getByTestId('nameFilter')); + }); + // Select option and enter first name + userEvent.click(screen.getByTestId('searchByFirstName')); + const firstNameInput = screen.getByPlaceholderText(/Search by First Name/i); + userEvent.type(firstNameInput, 'john{enter}'); + + await wait(700); + + expect(screen.getByText('John Doe')).toBeInTheDocument(); + expect(screen.queryByText('Sam Smith')).not.toBeInTheDocument(); + + expect(window.location).toBeAt('/blockuser/orgid'); + }); + + test('Testing Last Name Filter', async () => { + window.location.assign('/blockuser/orgid'); + + render( + + + + + + + + + , + ); + + await act(async () => { + userEvent.click(screen.getByTestId('userFilter')); + }); + userEvent.click(screen.getByTestId('showMembers')); + + await wait(); + + expect(screen.getByText('John Doe')).toBeInTheDocument(); + expect(screen.getByText('Sam Smith')).toBeInTheDocument(); + + // Open Dropdown + await act(async () => { + userEvent.click(screen.getByTestId('nameFilter')); + }); + // Select option and enter last name + userEvent.click(screen.getByTestId('searchByLastName')); + const lastNameInput = screen.getByPlaceholderText(/Search by Last Name/i); + userEvent.type(lastNameInput, 'doe{enter}'); + + await wait(700); + + expect(lastNameInput).toHaveValue('doe'); + expect(screen.getByText('John Doe')).toBeInTheDocument(); + expect(screen.queryByText('Sam Smith')).not.toBeInTheDocument(); + expect(window.location).toBeAt('/blockuser/orgid'); + }); + + test('Testing No Spammers Present', async () => { + window.location.assign('/blockuser/orgid'); + render( + + + + + + + + + , + ); + + await wait(); + expect(screen.getByText(/No spammer found/i)).toBeInTheDocument(); + expect(window.location).toBeAt('/blockuser/orgid'); + }); + + test('Testing All Members', async () => { + window.location.assign('/blockuser/orgid'); + + render( + + + + + + + + + + , + ); + await wait(); + await act(async () => { + userEvent.click(screen.getByTestId('userFilter')); + }); + userEvent.click(screen.getByTestId('showMembers')); + + await wait(700); + + expect(screen.getByTestId(/userFilter/i)).toHaveTextContent('All Members'); + expect(screen.getByText('John Doe')).toBeInTheDocument(); + expect(screen.getByText('Sam Smith')).toBeInTheDocument(); + + expect(window.location).toBeAt('/blockuser/orgid'); + }); + + test('Testing Blocked Users', async () => { + window.location.assign('/blockuser/orgid'); + + render( + + + + + + + + + + , + ); + + await act(async () => { + userEvent.click(screen.getByTestId('userFilter')); + }); + + userEvent.click(screen.getByTestId('showBlockedMembers')); + await wait(); + + expect(screen.getByText('John Doe')).toBeInTheDocument(); + expect(screen.queryByText('Sam Smith')).not.toBeInTheDocument(); + + expect(window.location).toBeAt('/blockuser/orgid'); + }); + + test('Testing table data getting rendered', async () => { + window.location.assign('/orglist/orgid'); + const link = new StaticMockLink(MOCKS, true); + render( + + + + + + + + + , + ); + await act(async () => { + userEvent.click(screen.getByTestId('userFilter')); + }); + userEvent.click(screen.getByTestId('showMembers')); + + await wait(); + + expect(screen.getByTestId(/userList/)).toBeInTheDocument(); + expect(screen.getAllByText('Block/Unblock')).toHaveLength(1); + expect(screen.getByText('John Doe')).toBeInTheDocument(); + expect(screen.getByText('Sam Smith')).toBeInTheDocument(); + }); + + test('Testing No Results Found', async () => { + window.location.assign('/blockuser/orgid'); + render( + + + + + + + + + , + ); + + const input = screen.getByPlaceholderText('Search By First Name'); + await act(async () => { + userEvent.type(input, 'Peter{enter}'); + }); + await wait(700); + expect( + screen.getByText(`No results found for "Peter"`), + ).toBeInTheDocument(); + expect(window.location).toBeAt('/blockuser/orgid'); + }); + + test('Testing Search functionality', async () => { + window.location.assign('/blockuser/orgid'); + + render( + + + + + + + + + + , + ); + await wait(); + const searchBar = screen.getByTestId(/searchByName/i); + const searchBtn = screen.getByTestId(/searchBtn/i); + expect(searchBar).toBeInTheDocument(); + userEvent.type(searchBar, 'Dummy{enter}'); + await wait(); + userEvent.clear(searchBar); + userEvent.type(searchBar, 'Dummy'); + userEvent.click(searchBtn); + await wait(); + userEvent.clear(searchBar); + userEvent.type(searchBar, ''); + userEvent.click(searchBtn); + }); +}); diff --git a/src/screens/BlockUser/BlockUser.tsx b/src/screens/BlockUser/BlockUser.tsx new file mode 100644 index 0000000000..df957e0c8a --- /dev/null +++ b/src/screens/BlockUser/BlockUser.tsx @@ -0,0 +1,312 @@ +import { useMutation, useQuery } from '@apollo/client'; +import React, { useEffect, useState } from 'react'; +import { Dropdown, Form, Table } from 'react-bootstrap'; +import Button from 'react-bootstrap/Button'; +import { toast } from 'react-toastify'; + +import { Search } from '@mui/icons-material'; +import SortIcon from '@mui/icons-material/Sort'; +import { + BLOCK_USER_MUTATION, + UNBLOCK_USER_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import { BLOCK_PAGE_MEMBER_LIST } from 'GraphQl/Queries/Queries'; +import TableLoader from 'components/TableLoader/TableLoader'; +import { useTranslation } from 'react-i18next'; +import { errorHandler } from 'utils/errorHandler'; +import styles from './BlockUser.module.css'; +import { useParams } from 'react-router-dom'; + +interface InterfaceMember { + _id: string; + email: string; + firstName: string; + lastName: string; + organizationsBlockedBy: { + _id: string; + __typename: 'Organization'; + }[]; + __typename: 'User'; +} + +const Requests = (): JSX.Element => { + const { t } = useTranslation('translation', { + keyPrefix: 'blockUnblockUser', + }); + const { t: tCommon } = useTranslation('common'); + + document.title = t('title'); + const { orgId: currentUrl } = useParams(); + const [membersData, setMembersData] = useState([]); + const [searchByFirstName, setSearchByFirstName] = useState(true); + const [searchByName, setSearchByName] = useState(''); + const [showBlockedMembers, setShowBlockedMembers] = useState(true); + + const { + data: memberData, + loading: loadingMembers, + error: memberError, + refetch: memberRefetch, + } = useQuery(BLOCK_PAGE_MEMBER_LIST, { + variables: { + orgId: currentUrl, + firstName_contains: '', + lastName_contains: '', + }, + }); + + const [blockUser] = useMutation(BLOCK_USER_MUTATION); + const [unBlockUser] = useMutation(UNBLOCK_USER_MUTATION); + + useEffect(() => { + if (!memberData) { + setMembersData([]); + return; + } + + if (showBlockedMembers == false) { + setMembersData(memberData?.organizationsMemberConnection.edges); + } else { + const blockUsers = memberData?.organizationsMemberConnection.edges.filter( + (user: InterfaceMember) => + user.organizationsBlockedBy.some((org) => org._id === currentUrl), + ); + setMembersData(blockUsers); + } + }, [memberData, showBlockedMembers]); + + const handleBlockUser = async (userId: string): Promise => { + try { + const { data } = await blockUser({ + variables: { + userId, + orgId: currentUrl, + }, + }); + /* istanbul ignore next */ + if (data) { + toast.success(t('blockedSuccessfully')); + memberRefetch(); + } + } catch (error: unknown) { + /* istanbul ignore next */ + errorHandler(t, error); + } + }; + + const handleUnBlockUser = async (userId: string): Promise => { + try { + const { data } = await unBlockUser({ + variables: { + userId, + orgId: currentUrl, + }, + }); + /* istanbul ignore next */ + if (data) { + toast.success(t('Un-BlockedSuccessfully')); + memberRefetch(); + } + } catch (error: unknown) { + /* istanbul ignore next */ + errorHandler(t, error); + } + }; + + /* istanbul ignore next */ + if (memberError) { + toast.error(memberError.message); + } + + const handleSearch = (value: string): void => { + setSearchByName(value); + memberRefetch({ + orgId: currentUrl, + firstName_contains: searchByFirstName ? value : '', + lastName_contains: searchByFirstName ? '' : value, + }); + }; + + const handleSearchByEnter = ( + e: React.KeyboardEvent, + ): void => { + if (e.key === 'Enter') { + const { value } = e.currentTarget; + handleSearch(value); + } + }; + + const handleSearchByBtnClick = (): void => { + const inputValue = + (document.getElementById('searchBlockedUsers') as HTMLInputElement) + ?.value || ''; + handleSearch(inputValue); + }; + + const headerTitles: string[] = [ + '#', + tCommon('name'), + tCommon('email'), + t('block_unblock'), + ]; + + return ( + <> +
    + {/* Buttons Container */} +
    +
    +
    + + +
    +
    +
    +
    + + +
    +
    +
    + {/* Table */} + {loadingMembers == false && + membersData.length === 0 && + searchByName.length > 0 ? ( +
    +

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

    +
    + ) : loadingMembers == false && membersData.length === 0 ? ( +
    +

    {t('noSpammerFound')}

    +
    + ) : ( +
    + {loadingMembers ? ( + + ) : ( + + + + {headerTitles.map((title: string, index: number) => { + return ( + + ); + })} + + + + {membersData.map((user, index: number) => { + return ( + + + + + + + ); + })} + +
    + {title} +
    {index + 1}{`${user.firstName} ${user.lastName}`}{user.email} + {user.organizationsBlockedBy.some( + (spam) => spam._id === currentUrl, + ) ? ( + + ) : ( + + )} +
    + )} +
    + )} +
    + + ); +}; + +export default Requests; diff --git a/src/screens/CommunityProfile/CommunityProfile.module.css b/src/screens/CommunityProfile/CommunityProfile.module.css new file mode 100644 index 0000000000..1e6eac2bae --- /dev/null +++ b/src/screens/CommunityProfile/CommunityProfile.module.css @@ -0,0 +1,41 @@ +.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; +} + +@media (max-width: 520px) { + .btn { + flex-direction: column; + justify-content: center; + } +} diff --git a/src/screens/CommunityProfile/CommunityProfile.test.tsx b/src/screens/CommunityProfile/CommunityProfile.test.tsx new file mode 100644 index 0000000000..6f1717bf30 --- /dev/null +++ b/src/screens/CommunityProfile/CommunityProfile.test.tsx @@ -0,0 +1,334 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { act, render, screen } 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 { StaticMockLink } from 'utils/StaticMockLink'; +import CommunityProfile from './CommunityProfile'; +import i18n from 'utils/i18nForTest'; +import { GET_COMMUNITY_DATA } from 'GraphQl/Queries/Queries'; +import { BrowserRouter } from 'react-router-dom'; +import { toast } from 'react-toastify'; +import { RESET_COMMUNITY, UPDATE_COMMUNITY } from 'GraphQl/Mutations/mutations'; + +const MOCKS1 = [ + { + request: { + query: GET_COMMUNITY_DATA, + }, + result: { + data: { + getCommunityData: null, + }, + }, + }, + { + request: { + query: UPDATE_COMMUNITY, + variables: { + data: { + name: 'Name', + websiteLink: 'https://website.com', + logo: 'data:image/png;base64,bG9nbw==', + socialMediaUrls: { + facebook: 'https://socialurl.com', + instagram: 'https://socialurl.com', + twitter: 'https://socialurl.com', + linkedIn: 'https://socialurl.com', + gitHub: 'https://socialurl.com', + youTube: 'https://socialurl.com', + reddit: 'https://socialurl.com', + slack: 'https://socialurl.com', + }, + }, + }, + }, + result: { + data: { + updateCommunity: true, + }, + }, + }, +]; + +const MOCKS2 = [ + { + request: { + query: GET_COMMUNITY_DATA, + }, + result: { + data: { + getCommunityData: { + _id: null, + name: null, + logoUrl: null, + websiteLink: null, + socialMediaUrls: { + facebook: null, + gitHub: null, + youTube: null, + instagram: null, + linkedIn: null, + reddit: null, + slack: null, + twitter: null, + }, + }, + }, + }, + }, + { + request: { + query: RESET_COMMUNITY, + variables: { + resetPreLoginImageryId: 'communityId', + }, + }, + result: { + data: { + resetCommunity: true, + }, + }, + }, +]; + +const MOCKS3 = [ + { + request: { + query: GET_COMMUNITY_DATA, + }, + result: { + data: { + getCommunityData: { + _id: 'communityId', + name: 'testName', + logoUrl: 'image.png', + websiteLink: 'http://websitelink.com', + socialMediaUrls: { + facebook: 'http://sociallink.com', + gitHub: 'http://sociallink.com', + youTube: 'http://sociallink.com', + instagram: 'http://sociallink.com', + linkedIn: 'http://sociallink.com', + reddit: 'http://sociallink.com', + slack: 'http://sociallink.com', + twitter: 'http://sociallink.com', + }, + }, + }, + }, + }, + { + request: { + query: RESET_COMMUNITY, + variables: { + resetPreLoginImageryId: 'communityId', + }, + }, + result: { + data: { + resetCommunity: true, + }, + }, + }, +]; + +const link1 = new StaticMockLink(MOCKS1, true); +const link2 = new StaticMockLink(MOCKS2, true); +const link3 = new StaticMockLink(MOCKS3, true); + +const profileVariables = { + name: 'Name', + websiteLink: 'https://website.com', + socialUrl: 'https://socialurl.com', + logo: new File(['logo'], 'test.png', { + type: 'image/png', + }), +}; + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }, +})); + +describe('Testing Community Profile Screen', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + test('Components should render properly', async () => { + window.location.assign('/communityProfile'); + + render( + + + + + + + , + ); + await wait(); + + expect(screen.getByPlaceholderText(/Community Name/i)).toBeInTheDocument(); + expect(screen.getByPlaceholderText(/Website Link/i)).toBeInTheDocument(); + expect(screen.getByTestId(/facebook/i)).toBeInTheDocument(); + expect(screen.getByTestId(/instagram/i)).toBeInTheDocument(); + expect(screen.getByTestId(/twitter/i)).toBeInTheDocument(); + expect(screen.getByTestId(/linkedIn/i)).toBeInTheDocument(); + expect(screen.getByTestId(/github/i)).toBeInTheDocument(); + expect(screen.getByTestId(/youtube/i)).toBeInTheDocument(); + expect(screen.getByTestId(/reddit/i)).toBeInTheDocument(); + expect(screen.getByTestId(/slack/i)).toBeInTheDocument(); + expect(screen.getByTestId('resetChangesBtn')).toBeInTheDocument(); + expect(screen.getByTestId('resetChangesBtn')).toBeDisabled(); + expect(screen.getByTestId('saveChangesBtn')).toBeInTheDocument(); + expect(screen.getByTestId('saveChangesBtn')).toBeDisabled(); + }); + + test('Testing all the input fields and update community data feature', async () => { + window.location.assign('/communityProfile'); + + await act(async () => { + render( + + + + + + + , + ); + await wait(); + + const communityName = screen.getByPlaceholderText(/Community Name/i); + const websiteLink = screen.getByPlaceholderText(/Website Link/i); + const logo = screen.getByTestId(/fileInput/i); + const facebook = screen.getByTestId(/facebook/i); + const instagram = screen.getByTestId(/instagram/i); + const twitter = screen.getByTestId(/twitter/i); + const linkedIn = screen.getByTestId(/linkedIn/i); + const github = screen.getByTestId(/github/i); + const youtube = screen.getByTestId(/youtube/i); + const reddit = screen.getByTestId(/reddit/i); + const slack = screen.getByTestId(/slack/i); + const saveChangesBtn = screen.getByTestId(/saveChangesBtn/i); + const resetChangeBtn = screen.getByTestId(/resetChangesBtn/i); + + userEvent.type(communityName, profileVariables.name); + userEvent.type(websiteLink, profileVariables.websiteLink); + userEvent.type(facebook, profileVariables.socialUrl); + userEvent.type(instagram, profileVariables.socialUrl); + userEvent.type(twitter, profileVariables.socialUrl); + userEvent.type(linkedIn, profileVariables.socialUrl); + userEvent.type(github, profileVariables.socialUrl); + userEvent.type(youtube, profileVariables.socialUrl); + userEvent.type(reddit, profileVariables.socialUrl); + userEvent.type(slack, profileVariables.socialUrl); + userEvent.upload(logo, profileVariables.logo); + await wait(); + + expect(communityName).toHaveValue(profileVariables.name); + expect(websiteLink).toHaveValue(profileVariables.websiteLink); + // expect(logo).toBeTruthy(); + expect(facebook).toHaveValue(profileVariables.socialUrl); + expect(instagram).toHaveValue(profileVariables.socialUrl); + expect(twitter).toHaveValue(profileVariables.socialUrl); + expect(linkedIn).toHaveValue(profileVariables.socialUrl); + expect(github).toHaveValue(profileVariables.socialUrl); + expect(youtube).toHaveValue(profileVariables.socialUrl); + expect(reddit).toHaveValue(profileVariables.socialUrl); + expect(slack).toHaveValue(profileVariables.socialUrl); + expect(saveChangesBtn).not.toBeDisabled(); + expect(resetChangeBtn).not.toBeDisabled(); + await wait(); + + userEvent.click(saveChangesBtn); + await wait(); + }); + }); + + test('If the queried data has some fields null then the input field should be empty', async () => { + render( + + + + + , + ); + await wait(); + + expect(screen.getByPlaceholderText(/Community Name/i)).toHaveValue(''); + expect(screen.getByPlaceholderText(/Website Link/i)).toHaveValue(''); + expect(screen.getByTestId(/facebook/i)).toHaveValue(''); + expect(screen.getByTestId(/instagram/i)).toHaveValue(''); + expect(screen.getByTestId(/twitter/i)).toHaveValue(''); + expect(screen.getByTestId(/linkedIn/i)).toHaveValue(''); + expect(screen.getByTestId(/github/i)).toHaveValue(''); + expect(screen.getByTestId(/youtube/i)).toHaveValue(''); + expect(screen.getByTestId(/reddit/i)).toHaveValue(''); + expect(screen.getByTestId(/slack/i)).toHaveValue(''); + }); + + test('Should clear out all the input field when click on Reset Changes button', async () => { + render( + + + + + , + ); + await wait(); + + const resetChangesBtn = screen.getByTestId('resetChangesBtn'); + userEvent.click(resetChangesBtn); + await wait(); + + expect(screen.getByPlaceholderText(/Community Name/i)).toHaveValue(''); + expect(screen.getByPlaceholderText(/Website Link/i)).toHaveValue(''); + expect(screen.getByTestId(/facebook/i)).toHaveValue(''); + expect(screen.getByTestId(/instagram/i)).toHaveValue(''); + expect(screen.getByTestId(/twitter/i)).toHaveValue(''); + expect(screen.getByTestId(/linkedIn/i)).toHaveValue(''); + expect(screen.getByTestId(/github/i)).toHaveValue(''); + expect(screen.getByTestId(/youtube/i)).toHaveValue(''); + expect(screen.getByTestId(/reddit/i)).toHaveValue(''); + expect(screen.getByTestId(/slack/i)).toHaveValue(''); + expect(toast.success).toHaveBeenCalled(); + }); + + test('Should have empty input fields when queried result is null', async () => { + render( + + + + + , + ); + + expect(screen.getByPlaceholderText(/Community Name/i)).toHaveValue(''); + expect(screen.getByPlaceholderText(/Website Link/i)).toHaveValue(''); + expect(screen.getByTestId(/facebook/i)).toHaveValue(''); + expect(screen.getByTestId(/instagram/i)).toHaveValue(''); + expect(screen.getByTestId(/twitter/i)).toHaveValue(''); + expect(screen.getByTestId(/linkedIn/i)).toHaveValue(''); + expect(screen.getByTestId(/github/i)).toHaveValue(''); + expect(screen.getByTestId(/youtube/i)).toHaveValue(''); + expect(screen.getByTestId(/reddit/i)).toHaveValue(''); + expect(screen.getByTestId(/slack/i)).toHaveValue(''); + }); +}); diff --git a/src/screens/CommunityProfile/CommunityProfile.tsx b/src/screens/CommunityProfile/CommunityProfile.tsx new file mode 100644 index 0000000000..96650c1ed8 --- /dev/null +++ b/src/screens/CommunityProfile/CommunityProfile.tsx @@ -0,0 +1,378 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { Button, Card, Form } from 'react-bootstrap'; +import { useMutation, useQuery } from '@apollo/client'; +import { toast } from 'react-toastify'; + +import Loader from 'components/Loader/Loader'; +import { GET_COMMUNITY_DATA } from 'GraphQl/Queries/Queries'; +import { UPDATE_COMMUNITY, RESET_COMMUNITY } from 'GraphQl/Mutations/mutations'; +import { + FacebookLogo, + InstagramLogo, + TwitterLogo, + LinkedInLogo, + GithubLogo, + YoutubeLogo, + RedditLogo, + SlackLogo, +} from 'assets/svgs/social-icons'; +import convertToBase64 from 'utils/convertToBase64'; +import styles from './CommunityProfile.module.css'; +import { errorHandler } from 'utils/errorHandler'; + +const CommunityProfile = (): JSX.Element => { + const { t } = useTranslation('translation', { + keyPrefix: 'communityProfile', + }); + const { t: tCommon } = useTranslation('common'); + + document.title = t('title'); + + type PreLoginImageryDataType = { + _id: string; + name: string | undefined; + websiteLink: string | undefined; + logoUrl: string | undefined; + socialMediaUrls: { + facebook: string | undefined; + instagram: string | undefined; + twitter: string | undefined; + linkedIn: string | undefined; + gitHub: string | undefined; + youTube: string | undefined; + reddit: string | undefined; + slack: string | undefined; + }; + }; + + const [profileVariable, setProfileVariable] = React.useState({ + name: '', + websiteLink: '', + logoUrl: '', + facebook: '', + instagram: '', + twitter: '', + linkedIn: '', + github: '', + youtube: '', + reddit: '', + slack: '', + }); + + const { data, loading } = useQuery(GET_COMMUNITY_DATA); + const [uploadPreLoginImagery] = useMutation(UPDATE_COMMUNITY); + const [resetPreLoginImagery] = useMutation(RESET_COMMUNITY); + + React.useEffect(() => { + const preLoginData: PreLoginImageryDataType | undefined = + data?.getCommunityData; + preLoginData && + setProfileVariable({ + name: preLoginData.name ?? '', + websiteLink: preLoginData.websiteLink ?? '', + logoUrl: preLoginData.logoUrl ?? '', + facebook: preLoginData.socialMediaUrls.facebook ?? '', + instagram: preLoginData.socialMediaUrls.instagram ?? '', + twitter: preLoginData.socialMediaUrls.twitter ?? '', + linkedIn: preLoginData.socialMediaUrls.linkedIn ?? '', + github: preLoginData.socialMediaUrls.gitHub ?? '', + youtube: preLoginData.socialMediaUrls.youTube ?? '', + reddit: preLoginData.socialMediaUrls.reddit ?? '', + slack: preLoginData.socialMediaUrls.slack ?? '', + }); + }, [data]); + + const handleOnChange = (e: React.ChangeEvent): void => { + setProfileVariable({ + ...profileVariable, + [e.target.name]: e.target.value, + }); + }; + + const handleOnSubmit = async ( + e: React.FormEvent, + ): Promise => { + e.preventDefault(); + try { + await uploadPreLoginImagery({ + variables: { + data: { + name: profileVariable.name, + websiteLink: profileVariable.websiteLink, + logo: profileVariable.logoUrl, + socialMediaUrls: { + facebook: profileVariable.facebook, + instagram: profileVariable.instagram, + twitter: profileVariable.twitter, + linkedIn: profileVariable.linkedIn, + gitHub: profileVariable.github, + youTube: profileVariable.youtube, + reddit: profileVariable.reddit, + slack: profileVariable.slack, + }, + }, + }, + }); + toast.success(t('profileChangedMsg')); + } catch (error: unknown) { + /* istanbul ignore next */ + errorHandler(t, error as Error); + } + }; + + const resetData = async (): Promise => { + const preLoginData: PreLoginImageryDataType | undefined = + data?.getCommunityData; + try { + setProfileVariable({ + name: '', + websiteLink: '', + logoUrl: '', + facebook: '', + instagram: '', + twitter: '', + linkedIn: '', + github: '', + youtube: '', + reddit: '', + slack: '', + }); + + await resetPreLoginImagery({ + variables: { + resetPreLoginImageryId: preLoginData?._id, + }, + }); + toast.success(t(`resetData`)); + } catch (error: unknown) { + /* istanbul ignore next */ + errorHandler(t, error as Error); + } + }; + + const isDisabled = (): boolean => { + if ( + profileVariable.name == '' && + profileVariable.websiteLink == '' && + profileVariable.logoUrl == '' + ) { + return true; + } else { + return false; + } + }; + + if (loading) { + ; + } + return ( + +
    +
    {t('editProfile')}
    +
    + +
    {t('communityProfileInfo')}
    +
    + + + {t('communityName')} + + + + + + {t('wesiteLink')} + + + + + {t('logo')} + + + {t('social')} +
    + Facebook Logo + +
    +
    + Instagram Logo + +
    +
    + Twitter Logo + +
    +
    + LinkedIn Logo + +
    +
    + Github Logo + +
    +
    + Youtube Logo + +
    +
    + Reddit Logo + +
    +
    + Slack Logo + +
    +
    +
    + + +
    +
    +
    +
    + ); +}; + +export default CommunityProfile; diff --git a/src/screens/EventManagement/EventManagement.module.css b/src/screens/EventManagement/EventManagement.module.css new file mode 100644 index 0000000000..f7e911887c --- /dev/null +++ b/src/screens/EventManagement/EventManagement.module.css @@ -0,0 +1,8 @@ +.content { + width: 100%; + height: 100%; + min-height: 80vh; + box-sizing: border-box; + background: #ffffff; + border-radius: 1rem; +} diff --git a/src/screens/EventManagement/EventManagement.test.tsx b/src/screens/EventManagement/EventManagement.test.tsx new file mode 100644 index 0000000000..fb851ec72f --- /dev/null +++ b/src/screens/EventManagement/EventManagement.test.tsx @@ -0,0 +1,114 @@ +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 i18nForTest from 'utils/i18nForTest'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import EventManagement from './EventManagement'; +import userEvent from '@testing-library/user-event'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { MOCKS_WITH_TIME } from 'components/EventManagement/Dashboard/EventDashboard.mocks'; +import useLocalStorage from 'utils/useLocalstorage'; +const { setItem } = useLocalStorage(); + +const mockWithTime = new StaticMockLink(MOCKS_WITH_TIME, true); + +const renderEventManagement = (): RenderResult => { + return render( + + + + + + } + /> + paramsError} + /> + eventsScreen} + /> + userEventsScreen + } + /> + + + + + , + ); +}; + +describe('Event Management', () => { + beforeAll(() => { + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: 'orgId', eventId: 'eventId' }), + })); + }); + + afterAll(() => { + jest.clearAllMocks(); + }); + + test('Testing Event Management Screen', async () => { + renderEventManagement(); + + const dashboardTab = await screen.findByTestId('eventDashboadTab'); + expect(dashboardTab).toBeInTheDocument(); + + const dashboardButton = screen.getByTestId('dashboardBtn'); + userEvent.click(dashboardButton); + + expect(dashboardTab).toBeInTheDocument(); + }); + test('Testing back button navigation when userType is SuperAdmin', async () => { + setItem('SuperAdmin', true); + renderEventManagement(); + + const backButton = screen.getByTestId('backBtn'); + userEvent.click(backButton); + await waitFor(() => { + const eventsScreen = screen.getByTestId('eventsScreen'); + expect(eventsScreen).toBeInTheDocument(); + }); + }); + + test('Testing event management tab switching', async () => { + renderEventManagement(); + + const registrantsButton = screen.getByTestId('registrantsBtn'); + userEvent.click(registrantsButton); + + const registrantsTab = screen.getByTestId('eventRegistrantsTab'); + expect(registrantsTab).toBeInTheDocument(); + + const eventActionsButton = screen.getByTestId('eventActionsBtn'); + userEvent.click(eventActionsButton); + + const eventActionsTab = screen.getByTestId('eventActionsTab'); + expect(eventActionsTab).toBeInTheDocument(); + + const eventAgendasButton = screen.getByTestId('eventAgendasBtn'); + userEvent.click(eventAgendasButton); + + const eventAgendasTab = screen.getByTestId('eventAgendasTab'); + expect(eventAgendasTab).toBeInTheDocument(); + + const eventStatsButton = screen.getByTestId('eventStatsBtn'); + userEvent.click(eventStatsButton); + + const eventStatsTab = screen.getByTestId('eventStatsTab'); + expect(eventStatsTab).toBeInTheDocument(); + }); +}); diff --git a/src/screens/EventManagement/EventManagement.tsx b/src/screens/EventManagement/EventManagement.tsx new file mode 100644 index 0000000000..4a2acdee1b --- /dev/null +++ b/src/screens/EventManagement/EventManagement.tsx @@ -0,0 +1,175 @@ +import React, { useState } from 'react'; +import Row from 'react-bootstrap/Row'; +import Col from 'react-bootstrap/Col'; +import styles from './EventManagement.module.css'; +import { Navigate, useNavigate, useParams } from 'react-router-dom'; +import { ReactComponent as AngleLeftIcon } from 'assets/svgs/angleLeft.svg'; +import { ReactComponent as EventDashboardIcon } from 'assets/svgs/eventDashboard.svg'; +import { ReactComponent as EventRegistrantsIcon } from 'assets/svgs/people.svg'; +import { ReactComponent as EventActionsIcon } from 'assets/svgs/settings.svg'; +import { ReactComponent as EventAgendaItemsIcon } from 'assets/svgs/agenda-items.svg'; +import { ReactComponent as EventStatisticsIcon } from 'assets/svgs/eventStats.svg'; +import { useTranslation } from 'react-i18next'; +import { Button } from 'react-bootstrap'; +import EventDashboard from 'components/EventManagement/Dashboard/EventDashboard'; +import EventActionItems from 'components/EventManagement/EventActionItems/EventActionItems'; +import EventAgendaItems from 'components/EventManagement/EventAgendaItems/EventAgendaItems'; +import useLocalStorage from 'utils/useLocalstorage'; + +const eventDashboardTabs: { + value: TabOptions; + icon: JSX.Element; +}[] = [ + { + value: 'dashboard', + icon: , + }, + { + value: 'registrants', + icon: , + }, + { + value: 'eventActions', + icon: , + }, + { + value: 'eventAgendas', + icon: , + }, + + { + value: 'eventStats', + icon: , + }, +]; + +type TabOptions = + | 'dashboard' + | 'registrants' + | 'eventActions' + | 'eventAgendas' + | 'eventStats'; + +const EventManagement = (): JSX.Element => { + const { t } = useTranslation('translation', { + keyPrefix: 'eventManagement', + }); + + const { getItem } = useLocalStorage(); + + const superAdmin = getItem('SuperAdmin'); + const adminFor = getItem('AdminFor'); + /*istanbul ignore next*/ + const userRole = superAdmin + ? 'SUPERADMIN' + : adminFor?.length > 0 + ? 'ADMIN' + : 'USER'; + + const { eventId, orgId } = useParams(); + /*istanbul ignore next*/ + if (!eventId || !orgId) { + return ; + } + + const navigate = useNavigate(); + const [tab, setTab] = useState('dashboard'); + + const handleClick = (value: TabOptions): void => { + setTab(value); + }; + + 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' + : 'text-secondary border-secondary-subtle px-4'; + const props = { + variant, + className, + key: value, + size: 'sm' as 'sm' | 'lg', + onClick: () => handleClick(value), + 'data-testid': `${value}Btn`, + }; + + return ( + + ); + }; + + return ( +
    +
    + { + /*istanbul ignore next*/ + userRole === 'USER' + ? navigate(`/user/events/${orgId}`) + : navigate(`/orgevents/${orgId}`); + }} + className="mt-1" + /> +
    + {eventDashboardTabs.map(renderButton)} +
    +
    + + + {(() => { + switch (tab) { + case 'dashboard': + return ( +
    + +
    + ); + case 'registrants': + return ( +
    +

    Event Registrants

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

    Event Statistics

    +
    + ); + } + })()} + +
    +
    + ); +}; + +export default EventManagement; diff --git a/src/screens/ForgotPassword/ForgotPassword.module.css b/src/screens/ForgotPassword/ForgotPassword.module.css new file mode 100644 index 0000000000..74e09aecc6 --- /dev/null +++ b/src/screens/ForgotPassword/ForgotPassword.module.css @@ -0,0 +1,71 @@ +.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.test.tsx b/src/screens/ForgotPassword/ForgotPassword.test.tsx new file mode 100644 index 0000000000..eb62cb0178 --- /dev/null +++ b/src/screens/ForgotPassword/ForgotPassword.test.tsx @@ -0,0 +1,412 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { act, render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import 'jest-localstorage-mock'; +import 'jest-location-mock'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { ToastContainer } from 'react-toastify'; + +import { GENERATE_OTP_MUTATION } from 'GraphQl/Mutations/mutations'; +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; +// import i18nForTest from 'utils/i18nForTest'; +import ForgotPassword from './ForgotPassword'; +import i18n from 'utils/i18nForTest'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem, removeItem } = useLocalStorage(); + +const MOCKS = [ + { + request: { + query: GENERATE_OTP_MUTATION, + variables: { + email: 'johndoe@gmail.com', + }, + }, + result: { + data: { + otp: { + otpToken: 'otpToken', + }, + }, + }, + }, + + { + request: { + query: GENERATE_OTP_MUTATION, + variables: { + email: 'notexists@gmail.com', + }, + }, + error: new Error('User not found'), + }, +]; + +const MOCKS_INTERNET_UNAVAILABLE = [ + { + request: { + query: GENERATE_OTP_MUTATION, + variables: { + email: 'johndoe@gmail.com', + }, + }, + error: new Error('Failed to fetch'), + }, +]; + +const link = new StaticMockLink(MOCKS, true); +const notWorkingLink = new StaticMockLink([], true); +const talawaApiUnavailableLink = new StaticMockLink( + MOCKS_INTERNET_UNAVAILABLE, + true, +); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const translations = { + ...JSON.parse( + JSON.stringify( + i18n.getDataByLanguage('en')?.translation.forgotPassword ?? {}, + ), + ), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), +}; + +beforeEach(() => { + setItem('IsLoggedIn', 'FALSE'); +}); +afterEach(() => { + localStorage.clear(); +}); + +describe('Testing Forgot Password screen', () => { + test('Component should be rendered properly', async () => { + window.location.assign('/orglist'); + + render( + + + + + + + + + , + ); + + await wait(); + + expect(screen.getByText(/Forgot Password/i)).toBeInTheDocument(); + expect(screen.getByText(/Registered Email/i)).toBeInTheDocument(); + expect(screen.getByText(/Get Otp/i)).toBeInTheDocument(); + expect(screen.getByText(/Back to Login/i)).toBeInTheDocument(); + expect(window.location).toBeAt('/orglist'); + }); + + test('Testing, If user is already loggedIn', async () => { + setItem('IsLoggedIn', 'TRUE'); + + render( + + + + + + + + + , + ); + + await wait(); + }); + + test('Testing get OTP functionality', async () => { + const formData = { + email: 'johndoe@gmail.com', + }; + + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.type( + screen.getByPlaceholderText(/Registered email/i), + formData.email, + ); + + userEvent.click(screen.getByText('Get OTP')); + await wait(); + }); + + test('Testing forgot password functionality', async () => { + const formData = { + userOtp: '12345', + newPassword: 'johnDoe', + confirmNewPassword: 'johnDoe', + email: 'johndoe@gmail.com', + }; + + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.type( + screen.getByPlaceholderText(/Registered email/i), + formData.email, + ); + + userEvent.click(screen.getByText('Get OTP')); + await wait(); + + userEvent.type(screen.getByPlaceholderText('e.g. 12345'), formData.userOtp); + userEvent.type(screen.getByTestId('newPassword'), formData.newPassword); + userEvent.type( + screen.getByTestId('confirmNewPassword'), + formData.confirmNewPassword, + ); + setItem('otpToken', 'lorem ipsum'); + userEvent.click(screen.getByText('Change Password')); + await wait(); + }); + + test('Testing forgot password functionality, if the otp got deleted from the local storage', async () => { + const formData = { + userOtp: '12345', + newPassword: 'johnDoe', + confirmNewPassword: 'johnDoe', + email: 'johndoe@gmail.com', + }; + + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.type( + screen.getByPlaceholderText(/Registered email/i), + formData.email, + ); + + userEvent.click(screen.getByText('Get OTP')); + await wait(); + + userEvent.type(screen.getByPlaceholderText('e.g. 12345'), formData.userOtp); + userEvent.type(screen.getByTestId('newPassword'), formData.newPassword); + userEvent.type( + screen.getByTestId('confirmNewPassword'), + formData.confirmNewPassword, + ); + removeItem('otpToken'); + userEvent.click(screen.getByText('Change Password')); + await wait(); + }); + + test('Testing forgot password functionality, when new password and confirm password is not same', async () => { + const formData = { + email: 'johndoe@gmail.com', + userOtp: '12345', + newPassword: 'johnDoe', + confirmNewPassword: 'doeJohn', + }; + + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.type( + screen.getByPlaceholderText(/Registered email/i), + formData.email, + ); + + userEvent.click(screen.getByText('Get OTP')); + await wait(); + + userEvent.type(screen.getByPlaceholderText('e.g. 12345'), formData.userOtp); + userEvent.type(screen.getByTestId('newPassword'), formData.newPassword); + userEvent.type( + screen.getByTestId('confirmNewPassword'), + formData.confirmNewPassword, + ); + + userEvent.click(screen.getByText('Change Password')); + }); + + test('Testing forgot password functionality, when the user is not found', async () => { + const formData = { + email: 'notexists@gmail.com', + }; + // setItem('otpToken', ''); + render( + + + + + + + + + + , + ); + + await wait(); + + userEvent.type( + screen.getByPlaceholderText(/Registered email/i), + formData.email, + ); + + userEvent.click(screen.getByText('Get OTP')); + await wait(); + + expect( + await screen.findByText(translations.emailNotRegistered), + ).toBeInTheDocument(); + }); + + test('Testing forgot password functionality, when there is an error except unregistered email and api failure', async () => { + render( + + + + + + + + + + , + ); + userEvent.click(screen.getByText('Get OTP')); + await wait(); + + expect( + await screen.findByText(translations.errorSendingMail), + ).toBeInTheDocument(); + }); + + test('Testing forgot password functionality, when talawa api failed', async () => { + const formData = { + email: 'johndoe@gmail.com', + }; + render( + + + + + + + + + + , + ); + + await wait(); + + userEvent.type( + screen.getByPlaceholderText(/Registered email/i), + formData.email, + ); + userEvent.click(screen.getByText('Get OTP')); + await wait(); + + expect( + await screen.findByText(translations.talawaApiUnavailable), + ).toBeInTheDocument(); + }); + + test('Testing forgot password functionality, when otp token is not present', async () => { + const formData = { + userOtp: '12345', + newPassword: 'johnDoe', + confirmNewPassword: 'johnDoe', + email: 'johndoe@gmail.com', + }; + + setItem('otpToken', ''); + + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.type( + screen.getByPlaceholderText(/Registered email/i), + formData.email, + ); + + userEvent.click(screen.getByText('Get OTP')); + await wait(); + + userEvent.type(screen.getByPlaceholderText('e.g. 12345'), formData.userOtp); + userEvent.type(screen.getByTestId('newPassword'), formData.newPassword); + userEvent.type( + screen.getByTestId('confirmNewPassword'), + formData.confirmNewPassword, + ); + userEvent.click(screen.getByText('Change Password')); + }); +}); diff --git a/src/screens/ForgotPassword/ForgotPassword.tsx b/src/screens/ForgotPassword/ForgotPassword.tsx new file mode 100644 index 0000000000..bf1e8c1ee8 --- /dev/null +++ b/src/screens/ForgotPassword/ForgotPassword.tsx @@ -0,0 +1,256 @@ +import { useMutation } from '@apollo/client'; +import type { ChangeEvent } from 'react'; +import React, { useEffect, useState } from 'react'; +import { Link } from 'react-router-dom'; +import { toast } from 'react-toastify'; + +import { + FORGOT_PASSWORD_MUTATION, + GENERATE_OTP_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import { ReactComponent as KeyLogo } from 'assets/svgs/key.svg'; + +import ArrowRightAlt from '@mui/icons-material/ArrowRightAlt'; +import Loader from 'components/Loader/Loader'; +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 useLocalStorage from 'utils/useLocalstorage'; + +const ForgotPassword = (): JSX.Element => { + const { t } = useTranslation('translation', { + keyPrefix: 'forgotPassword', + }); + const { t: tCommon } = useTranslation('common'); + const { t: tErrors } = useTranslation('errors'); + + document.title = t('title'); + + const { getItem, removeItem, setItem } = useLocalStorage(); + + const [showEnterEmail, setShowEnterEmail] = useState(true); + + const [registeredEmail, setregisteredEmail] = useState(''); + + const [forgotPassFormData, setForgotPassFormData] = useState({ + userOtp: '', + newPassword: '', + confirmNewPassword: '', + }); + + const [otp, { loading: otpLoading }] = useMutation(GENERATE_OTP_MUTATION); + const [forgotPassword, { loading: forgotPasswordLoading }] = useMutation( + FORGOT_PASSWORD_MUTATION, + ); + const isLoggedIn = getItem('IsLoggedIn'); + useEffect(() => { + if (isLoggedIn == 'TRUE') { + window.location.replace('/orglist'); + } + return () => { + removeItem('otpToken'); + }; + }, []); + + const getOTP = async (e: ChangeEvent): Promise => { + e.preventDefault(); + + try { + const { data } = await otp({ + variables: { + email: registeredEmail, + }, + }); + + if (data) { + setItem('otpToken', data.otp.otpToken); + toast.success(t('OTPsent')); + setShowEnterEmail(false); + } + } catch (error: unknown) { + if (error instanceof Error) { + if (error.message === 'User not found') { + toast.warn(tErrors('emailNotRegistered')); + } else if (error.message === 'Failed to fetch') { + toast.error(tErrors('talawaApiUnavailable')); + } else { + toast.error(tErrors('errorSendingMail')); + } + } + } + }; + + const submitForgotPassword = async ( + e: ChangeEvent, + ): Promise => { + e.preventDefault(); + const { userOtp, newPassword, confirmNewPassword } = forgotPassFormData; + + if (newPassword !== confirmNewPassword) { + toast.error(t('passwordMismatches')); + return; + } + + const otpToken = getItem('otpToken'); + + if (!otpToken) { + return; + } + + try { + const { data } = await forgotPassword({ + variables: { + userOtp, + newPassword, + otpToken, + }, + }); + + /* istanbul ignore next */ + if (data) { + toast.success(t('passwordChanges')); + setShowEnterEmail(true); + setForgotPassFormData({ + userOtp: '', + newPassword: '', + confirmNewPassword: '', + }); + } + } catch (error: unknown) { + setShowEnterEmail(true); + /* istanbul ignore next */ + errorHandler(t, error); + } + }; + + if (otpLoading || forgotPasswordLoading) { + return ; + } + return ( + <> +
    +
    +
    +
    +
    +
    + +
    +

    + {tCommon('forgotPassword')} +

    + {showEnterEmail ? ( +
    +
    + + {t('registeredEmail')}: + +
    + + setregisteredEmail(e.target.value) + } + /> +
    + +
    +
    + ) : ( +
    +
    + {t('enterOtp')}: + + setForgotPassFormData({ + ...forgotPassFormData, + userOtp: e.target.value, + }) + } + /> + + {t('enterNewPassword')}: + + + setForgotPassFormData({ + ...forgotPassFormData, + newPassword: e.target.value, + }) + } + /> + + {t('cofirmNewPassword')}: + + + setForgotPassFormData({ + ...forgotPassFormData, + confirmNewPassword: e.target.value, + }) + } + /> + + +
    + )} +
    + + + {t('backToLogin')} + +
    +
    +
    +
    +
    + + ); +}; + +export default ForgotPassword; diff --git a/src/screens/FundCampaignPledge/FundCampaignPledge.module.css b/src/screens/FundCampaignPledge/FundCampaignPledge.module.css new file mode 100644 index 0000000000..c46adfada3 --- /dev/null +++ b/src/screens/FundCampaignPledge/FundCampaignPledge.module.css @@ -0,0 +1,259 @@ +.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; +} + +.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; +} + +.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; +} + +.noOutline input { + outline: none; +} + +.overviewContainer { + display: flex; + gap: 7rem; + width: 100%; + justify-content: space-between; + margin: 1.5rem 0 0 0; + padding: 1.25rem 2rem; + background-color: rgba(255, 255, 255, 0.591); + + box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px; + border-radius: 0.5rem; +} + +.titleContainer { + display: flex; + flex-direction: column; + gap: 0.6rem; +} + +.titleContainer h3 { + font-size: 1.75rem; + font-weight: 750; + color: #5e5e5e; + margin-top: 0.2rem; +} + +.titleContainer span { + font-size: 0.9rem; + margin-left: 0.5rem; + font-weight: lighter; + color: #707070; +} + +.raisedAmount { + display: flex; + justify-content: center; + align-items: center; + font-size: 1.25rem; + font-weight: 750; + color: #5e5e5e; +} + +.progressContainer { + display: flex; + flex-direction: column; + gap: 0.5rem; + flex-grow: 1; +} + +.progress { + margin-top: 0.2rem; + display: flex; + flex-direction: column; + gap: 0.3rem; +} + +.endpoints { + display: flex; + position: relative; + font-size: 0.85rem; +} + +.start { + position: absolute; + top: 0px; +} + +.end { + position: absolute; + top: 0px; + right: 0px; +} + +.moreContainer { + display: flex; + align-items: center; +} + +.moreContainer:hover { + text-decoration: underline; + cursor: pointer; +} + +.popup { + z-index: 50; + border-radius: 0.5rem; + font-family: sans-serif; + font-weight: 500; + font-size: 0.875rem; + margin-top: 0.5rem; + padding: 0.75rem; + border: 1px solid #e2e8f0; + background-color: white; + color: #1e293b; + box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 0.15); + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.popupExtra { + max-height: 15rem; + overflow-y: auto; +} + +.toggleGroup { + width: 50%; + min-width: 27.75rem; + margin: 0.5rem 0rem; +} + +.toggleBtn { + padding: 0rem; + height: 30px; + display: flex; + justify-content: center; + align-items: center; +} + +.toggleBtn:hover { + color: #31bb6b !important; +} + +input[type='radio']:checked + label { + background-color: #31bb6a50 !important; +} + +input[type='radio']:checked + label:hover { + color: black !important; +} diff --git a/src/screens/FundCampaignPledge/FundCampaignPledge.test.tsx b/src/screens/FundCampaignPledge/FundCampaignPledge.test.tsx new file mode 100644 index 0000000000..25e049e19d --- /dev/null +++ b/src/screens/FundCampaignPledge/FundCampaignPledge.test.tsx @@ -0,0 +1,355 @@ +import { MockedProvider } from '@apollo/react-testing'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import type { RenderResult } from '@testing-library/react'; +import { + cleanup, + fireEvent, + render, + screen, + waitFor, +} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18nForTest from '../../utils/i18nForTest'; +import FundCampaignPledge from './FundCampaignPledge'; +import { + EMPTY_MOCKS, + MOCKS, + MOCKS_FUND_CAMPAIGN_PLEDGE_ERROR, +} from './PledgesMocks'; +import React from 'react'; +import type { ApolloLink } from '@apollo/client'; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); +jest.mock('@mui/x-date-pickers/DateTimePicker', () => { + return { + DateTimePicker: jest.requireActual( + '@mui/x-date-pickers/DesktopDateTimePicker', + ).DesktopDateTimePicker, + }; +}); + +const link1 = new StaticMockLink(MOCKS); +const link2 = new StaticMockLink(MOCKS_FUND_CAMPAIGN_PLEDGE_ERROR); +const link3 = new StaticMockLink(EMPTY_MOCKS); +const translations = JSON.parse( + JSON.stringify(i18nForTest.getDataByLanguage('en')?.translation.pledges), +); + +const renderFundCampaignPledge = (link: ApolloLink): RenderResult => { + return render( + + + + + + + } + /> +
    } + /> + + + + + + , + ); +}; + +describe('Testing Campaign Pledge Screen', () => { + beforeAll(() => { + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: 'orgId', fundCampaignId: 'fundCampaignId' }), + })); + }); + + afterAll(() => { + jest.clearAllMocks(); + }); + + afterEach(() => { + cleanup(); + }); + + it('should render the Campaign Pledge screen', async () => { + renderFundCampaignPledge(link1); + await waitFor(() => { + expect(screen.getByTestId('searchPledger')).toBeInTheDocument(); + }); + }); + + it('should redirect to fallback URL if URL params are undefined', async () => { + render( + + + + + + } + /> + } + /> + + + + + , + ); + await waitFor(() => { + expect(screen.getByTestId('paramsError')).toBeInTheDocument(); + }); + }); + + it('open and closes Create Pledge modal', async () => { + renderFundCampaignPledge(link1); + + const addPledgeBtn = await screen.findByTestId('addPledgeBtn'); + expect(addPledgeBtn).toBeInTheDocument(); + userEvent.click(addPledgeBtn); + + await waitFor(() => + expect(screen.getAllByText(translations.createPledge)).toHaveLength(2), + ); + userEvent.click(screen.getByTestId('pledgeModalCloseBtn')); + await waitFor(() => + expect(screen.queryByTestId('pledgeModalCloseBtn')).toBeNull(), + ); + }); + + it('open and closes update pledge modal', async () => { + renderFundCampaignPledge(link1); + + const editPledgeBtn = await screen.findAllByTestId('editPledgeBtn'); + await waitFor(() => expect(editPledgeBtn[0]).toBeInTheDocument()); + userEvent.click(editPledgeBtn[0]); + + await waitFor(() => + expect(screen.getByText(translations.editPledge)).toBeInTheDocument(), + ); + userEvent.click(screen.getByTestId('pledgeModalCloseBtn')); + await waitFor(() => + expect(screen.queryByTestId('pledgeModalCloseBtn')).toBeNull(), + ); + }); + + it('open and closes delete pledge modal', async () => { + renderFundCampaignPledge(link1); + + const deletePledgeBtn = await screen.findAllByTestId('deletePledgeBtn'); + await waitFor(() => expect(deletePledgeBtn[0]).toBeInTheDocument()); + userEvent.click(deletePledgeBtn[0]); + + await waitFor(() => + expect(screen.getByText(translations.deletePledge)).toBeInTheDocument(), + ); + userEvent.click(screen.getByTestId('deletePledgeCloseBtn')); + await waitFor(() => + expect(screen.queryByTestId('deletePledgeCloseBtn')).toBeNull(), + ); + }); + + it('Search the Pledges list by Users', async () => { + renderFundCampaignPledge(link1); + const searchPledger = await screen.findByTestId('searchPledger'); + fireEvent.change(searchPledger, { + target: { value: 'John' }, + }); + + await waitFor(() => { + expect(screen.getByText('John Doe')).toBeInTheDocument(); + expect(screen.queryByText('Jane Doe')).toBeNull(); + }); + }); + + it('should render the Campaign Pledge screen with error', async () => { + renderFundCampaignPledge(link2); + await waitFor(() => { + expect(screen.getByTestId('errorMsg')).toBeInTheDocument(); + }); + }); + + it('renders the empty pledge component', async () => { + renderFundCampaignPledge(link3); + await waitFor(() => + expect(screen.getByText(translations.noPledges)).toBeInTheDocument(), + ); + }); + + it('check if user image renders', async () => { + renderFundCampaignPledge(link1); + await waitFor(() => { + expect(screen.getByTestId('searchPledger')).toBeInTheDocument(); + }); + + const image = await screen.findByTestId('image1'); + expect(image).toBeInTheDocument(); + expect(image).toHaveAttribute('src', 'img-url'); + }); + + it('should render extraUserDetails in Popup', async () => { + renderFundCampaignPledge(link1); + await waitFor(() => { + expect(screen.getByTestId('searchPledger')).toBeInTheDocument(); + }); + + expect(screen.getByText('John Doe')).toBeInTheDocument(); + expect(screen.getByText('John Doe2')).toBeInTheDocument(); + expect(screen.queryByText('John Doe3')).toBeNull(); + expect(screen.queryByText('John Doe4')).toBeNull(); + + const moreContainer = await screen.findAllByTestId('moreContainer'); + userEvent.click(moreContainer[0]); + + await waitFor(() => { + expect(screen.getByText('John Doe3')).toBeInTheDocument(); + expect(screen.getByText('John Doe4')).toBeInTheDocument(); + expect(screen.getByTestId('extra1')).toBeInTheDocument(); + expect(screen.getByTestId('extra2')).toBeInTheDocument(); + expect(screen.getByTestId('extraAvatar8')).toBeInTheDocument(); + const image = screen.getByTestId('extraImage1'); + expect(image).toBeInTheDocument(); + expect(image).toHaveAttribute('src', 'img-url3'); + }); + + userEvent.click(moreContainer[0]); + await waitFor(() => { + expect(screen.queryByText('John Doe3')).toBeNull(); + expect(screen.queryByText('John Doe4')).toBeNull(); + }); + }); + + it('should render Progress Bar with Raised amount (CONSTANT) & Pledged Amount', async () => { + renderFundCampaignPledge(link1); + await waitFor(() => { + expect(screen.getByTestId('searchPledger')).toBeInTheDocument(); + }); + const raised = screen.getByText('Raised amount'); + const pledged = screen.getByText('Pledged amount'); + expect(pledged).toBeInTheDocument(); + expect(raised).toBeInTheDocument(); + + userEvent.click(raised); + + await waitFor(() => { + expect(screen.getByTestId('progressBar')).toBeInTheDocument(); + expect(screen.getByTestId('progressBar')).toHaveTextContent('$0'); + }); + + userEvent.click(pledged); + + await waitFor(() => { + expect(screen.getByTestId('progressBar')).toBeInTheDocument(); + expect(screen.getByTestId('progressBar')).toHaveTextContent('$300'); + }); + }); + + it('Sort the Pledges list by Lowest Amount', async () => { + renderFundCampaignPledge(link1); + + const searchPledger = await screen.findByTestId('searchPledger'); + expect(searchPledger).toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('filter')); + await waitFor(() => { + expect(screen.getByTestId('amount_ASC')).toBeInTheDocument(); + }); + fireEvent.click(screen.getByTestId('amount_ASC')); + + await waitFor(() => { + expect(screen.getByText('John Doe')).toBeInTheDocument(); + expect(screen.queryByText('Jane Doe')).toBeInTheDocument(); + }); + + await waitFor(() => { + expect(screen.getAllByTestId('amountCell')[0]).toHaveTextContent('100'); + }); + }); + + it('Sort the Pledges list by Highest Amount', async () => { + renderFundCampaignPledge(link1); + + const searchPledger = await screen.findByTestId('searchPledger'); + expect(searchPledger).toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('filter')); + await waitFor(() => { + expect(screen.getByTestId('amount_DESC')).toBeInTheDocument(); + }); + fireEvent.click(screen.getByTestId('amount_DESC')); + + await waitFor(() => { + expect(screen.getByText('John Doe')).toBeInTheDocument(); + expect(screen.queryByText('Jane Doe')).toBeInTheDocument(); + }); + + await waitFor(() => { + expect(screen.getAllByTestId('amountCell')[0]).toHaveTextContent('200'); + }); + }); + + it('Sort the Pledges list by latest endDate', async () => { + renderFundCampaignPledge(link1); + + const searchPledger = await screen.findByTestId('searchPledger'); + expect(searchPledger).toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('filter')); + await waitFor(() => { + expect(screen.getByTestId('endDate_DESC')).toBeInTheDocument(); + }); + fireEvent.click(screen.getByTestId('endDate_DESC')); + + await waitFor(() => { + expect(screen.getByText('John Doe')).toBeInTheDocument(); + expect(screen.queryByText('Jane Doe')).toBeInTheDocument(); + }); + + await waitFor(() => { + expect(screen.getAllByTestId('amountCell')[0]).toHaveTextContent('100'); + }); + }); + + it('Sort the Pledges list by earliest endDate', async () => { + renderFundCampaignPledge(link1); + + const searchPledger = await screen.findByTestId('searchPledger'); + expect(searchPledger).toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('filter')); + await waitFor(() => { + expect(screen.getByTestId('endDate_ASC')).toBeInTheDocument(); + }); + fireEvent.click(screen.getByTestId('endDate_ASC')); + + await waitFor(() => { + expect(screen.getByText('John Doe')).toBeInTheDocument(); + expect(screen.queryByText('Jane Doe')).toBeInTheDocument(); + }); + + await waitFor(() => { + expect(screen.getAllByTestId('amountCell')[0]).toHaveTextContent('200'); + }); + }); +}); diff --git a/src/screens/FundCampaignPledge/FundCampaignPledge.tsx b/src/screens/FundCampaignPledge/FundCampaignPledge.tsx new file mode 100644 index 0000000000..9798336412 --- /dev/null +++ b/src/screens/FundCampaignPledge/FundCampaignPledge.tsx @@ -0,0 +1,627 @@ +import { useQuery, type ApolloQueryResult } from '@apollo/client'; +import { Search, Sort, WarningAmberRounded } from '@mui/icons-material'; +import { FUND_CAMPAIGN_PLEDGE } from 'GraphQl/Queries/fundQueries'; +import Loader from 'components/Loader/Loader'; +import { Unstable_Popup as BasePopup } from '@mui/base/Unstable_Popup'; +import dayjs from 'dayjs'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { Button, Dropdown, Form } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; +import { Navigate, useParams } from 'react-router-dom'; +import { currencySymbols } from 'utils/currency'; +import styles from './FundCampaignPledge.module.css'; +import PledgeDeleteModal from './PledgeDeleteModal'; +import PledgeModal from './PledgeModal'; +import { Breadcrumbs, Link, Stack, Typography } from '@mui/material'; +import { DataGrid } from '@mui/x-data-grid'; +import Avatar from 'components/Avatar/Avatar'; +import type { GridCellParams, GridColDef } from '@mui/x-data-grid'; +import type { + InterfacePledgeInfo, + InterfacePledger, + InterfaceQueryFundCampaignsPledges, +} from 'utils/interfaces'; +import ProgressBar from 'react-bootstrap/ProgressBar'; + +interface InterfaceCampaignInfo { + name: string; + goal: number; + startDate: Date; + endDate: Date; + currency: string; +} + +enum ModalState { + SAME = 'same', + DELETE = 'delete', +} + +const dataGridStyle = { + '&.MuiDataGrid-root .MuiDataGrid-cell:focus-within': { + outline: 'none !important', + }, + '&.MuiDataGrid-root .MuiDataGrid-columnHeader:focus-within': { + outline: 'none', + }, + '& .MuiDataGrid-row:hover': { + backgroundColor: 'transparent', + }, + '& .MuiDataGrid-row.Mui-hovered': { + backgroundColor: 'transparent', + }, + '& .MuiDataGrid-root': { + borderRadius: '0.5rem', + }, + '& .MuiDataGrid-main': { + borderRadius: '0.5rem', + }, +}; + +const fundCampaignPledge = (): JSX.Element => { + const { t } = useTranslation('translation', { + keyPrefix: 'pledges', + }); + const { t: tCommon } = useTranslation('common'); + + const { fundCampaignId, orgId } = useParams(); + if (!fundCampaignId || !orgId) { + return ; + } + + const [campaignInfo, setCampaignInfo] = useState({ + name: '', + goal: 0, + startDate: new Date(), + endDate: new Date(), + currency: '', + }); + + const [modalState, setModalState] = useState<{ + [key in ModalState]: boolean; + }>({ + [ModalState.SAME]: false, + [ModalState.DELETE]: false, + }); + + const [anchor, setAnchor] = useState(null); + const [extraUsers, setExtraUsers] = useState([]); + const [progressIndicator, setProgressIndicator] = useState< + 'raised' | 'pledged' + >('pledged'); + const open = Boolean(anchor); + const id = open ? 'simple-popup' : undefined; + const [pledgeModalMode, setPledgeModalMode] = useState<'edit' | 'create'>( + 'create', + ); + const [pledge, setPledge] = useState(null); + const [searchTerm, setSearchTerm] = useState(''); + + const [sortBy, setSortBy] = useState< + 'amount_ASC' | 'amount_DESC' | 'endDate_ASC' | 'endDate_DESC' + >('endDate_DESC'); + + const { + data: pledgeData, + loading: pledgeLoading, + error: pledgeError, + refetch: refetchPledge, + }: { + data?: { + getFundraisingCampaignById: InterfaceQueryFundCampaignsPledges; + }; + loading: boolean; + error?: Error | undefined; + refetch: () => Promise< + ApolloQueryResult<{ + getFundraisingCampaignById: InterfaceQueryFundCampaignsPledges; + }> + >; + } = useQuery(FUND_CAMPAIGN_PLEDGE, { + variables: { + id: fundCampaignId, + orderBy: sortBy, + }, + }); + + const endDate = dayjs( + pledgeData?.getFundraisingCampaignById?.endDate, + 'YYYY-MM-DD', + ).toDate(); + + const { pledges, totalPledged } = useMemo(() => { + let totalPledged = 0; + const pledges = + pledgeData?.getFundraisingCampaignById.pledges.filter((pledge) => { + totalPledged += pledge.amount; + const search = searchTerm.toLowerCase(); + return pledge.users.some((user) => { + const fullName = `${user.firstName} ${user.lastName}`; + return fullName.toLowerCase().includes(search); + }); + }) ?? []; + return { pledges, totalPledged }; + }, [pledgeData, searchTerm]); + + useEffect(() => { + if (pledgeData) { + setCampaignInfo({ + name: pledgeData.getFundraisingCampaignById.name, + goal: pledgeData.getFundraisingCampaignById.fundingGoal, + startDate: pledgeData.getFundraisingCampaignById.startDate, + endDate: pledgeData.getFundraisingCampaignById.endDate, + currency: pledgeData.getFundraisingCampaignById.currency, + }); + } + }, [pledgeData]); + + useEffect(() => { + refetchPledge(); + }, [sortBy, refetchPledge]); + + const openModal = (modal: ModalState): void => { + setModalState((prevState) => ({ ...prevState, [modal]: true })); + }; + + const closeModal = (modal: ModalState): void => { + setModalState((prevState) => ({ ...prevState, [modal]: false })); + }; + + const handleOpenModal = useCallback( + (pledge: InterfacePledgeInfo | null, mode: 'edit' | 'create'): void => { + setPledge(pledge); + setPledgeModalMode(mode); + openModal(ModalState.SAME); + }, + [openModal], + ); + + const handleDeleteClick = useCallback( + (pledge: InterfacePledgeInfo): void => { + setPledge(pledge); + openModal(ModalState.DELETE); + }, + [openModal], + ); + + const handleClick = ( + event: React.MouseEvent, + users: InterfacePledger[], + ): void => { + setExtraUsers(users); + setAnchor(anchor ? null : event.currentTarget); + }; + + if (pledgeLoading) return ; + if (pledgeError) { + return ( +
    +
    + +
    + Error occured while loading Funds +
    + {pledgeError.message} +
    +
    +
    + ); + } + + const columns: GridColDef[] = [ + { + field: 'pledgers', + headerName: 'Pledgers', + flex: 3, + minWidth: 50, + align: 'left', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return ( +
    + {params.row.users + .slice(0, 2) + .map((user: InterfacePledger, index: number) => ( +
    + {user.image ? ( + pledge + ) : ( +
    + +
    + )} + + {user.firstName + ' ' + user.lastName} + +
    + ))} + {params.row.users.length > 2 && ( +
    handleClick(e, params.row.users.slice(2))} + > + +{params.row.users.length - 2} more... +
    + )} +
    + ); + }, + }, + { + field: 'startDate', + headerName: 'Start Date', + flex: 1, + minWidth: 150, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return dayjs(params.row.startDate).format('DD/MM/YYYY'); + }, + }, + { + field: 'endDate', + headerName: 'End Date', + minWidth: 150, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + flex: 1, + sortable: false, + renderCell: (params: GridCellParams) => { + return dayjs(params.row.endDate).format('DD/MM/YYYY'); + }, + }, + { + field: 'amount', + headerName: 'Pledged', + flex: 1, + minWidth: 100, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return ( +
    + { + currencySymbols[ + params.row.currency as keyof typeof currencySymbols + ] + } + {params.row.amount} +
    + ); + }, + }, + { + field: 'donated', + headerName: 'Donated', + flex: 1, + minWidth: 100, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return ( +
    + { + currencySymbols[ + params.row.currency as keyof typeof currencySymbols + ] + } + 0 +
    + ); + }, + }, + { + field: 'action', + headerName: 'Action', + flex: 1, + minWidth: 100, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return ( + <> + + + + ); + }, + }, + ]; + + return ( +
    + + history.go(-2) + } + > + {tCommon('Funds')} + + history.back() + } + > + {t('campaigns')} + + {t('pledges')} + +
    +
    +

    {campaignInfo?.name}

    + + {t('endsOn')} {campaignInfo?.endDate.toString()} + +
    +
    +
    +
    + setProgressIndicator('pledged')} + /> + + + setProgressIndicator('raised')} + checked={progressIndicator === 'raised'} + /> + +
    +
    + +
    + +
    +
    $0
    +
    ${campaignInfo?.goal}
    +
    +
    +
    +
    +
    +
    + setSearchTerm(e.target.value)} + data-testid="searchPledger" + /> + +
    +
    +
    + + + + {tCommon('sort')} + + + setSortBy('amount_ASC')} + data-testid="amount_ASC" + > + {t('lowestAmount')} + + setSortBy('amount_DESC')} + data-testid="amount_DESC" + > + {t('highestAmount')} + + setSortBy('endDate_DESC')} + data-testid="endDate_DESC" + > + {t('latestEndDate')} + + setSortBy('endDate_ASC')} + data-testid="endDate_ASC" + > + {t('earliestEndDate')} + + + +
    +
    + +
    +
    +
    + row._id} + slots={{ + noRowsOverlay: () => ( + + {t('noPledges')} + + ), + }} + sx={dataGridStyle} + getRowClassName={() => `${styles.rowBackground}`} + autoHeight + rowHeight={65} + rows={pledges.map((pledge) => ({ + _id: pledge._id, + users: pledge.users, + startDate: pledge.startDate, + endDate: pledge.endDate, + amount: pledge.amount, + currency: pledge.currency, + }))} + columns={columns} + isRowSelectable={() => false} + /> + {/* Update Pledge ModalState */} + closeModal(ModalState.SAME)} + campaignId={fundCampaignId} + orgId={orgId} + pledge={pledge} + refetchPledge={refetchPledge} + endDate={pledgeData?.getFundraisingCampaignById.endDate as Date} + mode={pledgeModalMode} + /> + {/* Delete Pledge ModalState */} + closeModal(ModalState.DELETE)} + pledge={pledge} + refetchPledge={refetchPledge} + /> + 4 ? styles.popupExtra : ''}`} + > + {extraUsers.map((user: InterfacePledger, index: number) => ( +
    + {user.image ? ( + pledger + ) : ( +
    + +
    + )} + + {user.firstName + ' ' + user.lastName} + +
    + ))} +
    +
    + ); +}; +export default fundCampaignPledge; diff --git a/src/screens/FundCampaignPledge/PledgeDeleteModal.test.tsx b/src/screens/FundCampaignPledge/PledgeDeleteModal.test.tsx new file mode 100644 index 0000000000..dbaae76504 --- /dev/null +++ b/src/screens/FundCampaignPledge/PledgeDeleteModal.test.tsx @@ -0,0 +1,101 @@ +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 type { InterfaceDeletePledgeModal } from './PledgeDeleteModal'; +import PledgeDeleteModal from './PledgeDeleteModal'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import i18nForTest from '../../utils/i18nForTest'; +import { MOCKS_DELETE_PLEDGE_ERROR, MOCKS } from './PledgesMocks'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { toast } from 'react-toastify'; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +const link = new StaticMockLink(MOCKS); +const link2 = new StaticMockLink(MOCKS_DELETE_PLEDGE_ERROR); +const translations = JSON.parse( + JSON.stringify(i18nForTest.getDataByLanguage('en')?.translation.pledges), +); + +const pledgeProps: InterfaceDeletePledgeModal = { + isOpen: true, + hide: jest.fn(), + pledge: { + _id: '1', + amount: 100, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-10', + users: [ + { + _id: '1', + firstName: 'John', + lastName: 'Doe', + image: 'img-url', + }, + ], + }, + refetchPledge: jest.fn(), +}; + +const renderPledgeDeleteModal = ( + link: ApolloLink, + props: InterfaceDeletePledgeModal, +): RenderResult => { + return render( + + + + + + + + + + + , + ); +}; + +describe('PledgeDeleteModal', () => { + it('should render PledgeDeleteModal', () => { + renderPledgeDeleteModal(link, pledgeProps); + expect(screen.getByTestId('deletePledgeCloseBtn')).toBeInTheDocument(); + }); + + it('should successfully Delete pledge', async () => { + renderPledgeDeleteModal(link, pledgeProps); + expect(screen.getByTestId('deletePledgeCloseBtn')).toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('deleteyesbtn')); + + await waitFor(() => { + expect(pledgeProps.refetchPledge).toHaveBeenCalled(); + expect(pledgeProps.hide).toHaveBeenCalled(); + expect(toast.success).toHaveBeenCalledWith(translations.pledgeDeleted); + }); + }); + + it('should fail to Delete pledge', async () => { + renderPledgeDeleteModal(link2, pledgeProps); + expect(screen.getByTestId('deletePledgeCloseBtn')).toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('deleteyesbtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith('Error deleting pledge'); + }); + }); +}); diff --git a/src/screens/FundCampaignPledge/PledgeDeleteModal.tsx b/src/screens/FundCampaignPledge/PledgeDeleteModal.tsx new file mode 100644 index 0000000000..a16d0df905 --- /dev/null +++ b/src/screens/FundCampaignPledge/PledgeDeleteModal.tsx @@ -0,0 +1,77 @@ +import { Button, Modal } from 'react-bootstrap'; +import styles from './FundCampaignPledge.module.css'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useMutation } from '@apollo/client'; +import { DELETE_PLEDGE } from 'GraphQl/Mutations/PledgeMutation'; +import type { InterfacePledgeInfo } from 'utils/interfaces'; +import { toast } from 'react-toastify'; + +export interface InterfaceDeletePledgeModal { + isOpen: boolean; + hide: () => void; + pledge: InterfacePledgeInfo | null; + refetchPledge: () => void; +} +const PledgeDeleteModal: React.FC = ({ + isOpen, + hide, + pledge, + refetchPledge, +}) => { + const { t } = useTranslation('translation', { + keyPrefix: 'pledges', + }); + const { t: tCommon } = useTranslation('common'); + + const [deletePledge] = useMutation(DELETE_PLEDGE); + + const deleteHandler = async (): Promise => { + try { + await deletePledge({ + variables: { + id: pledge?._id, + }, + }); + refetchPledge(); + hide(); + toast.success(t('pledgeDeleted')); + } catch (error: unknown) { + toast.error((error as Error).message); + } + }; + return ( + <> + + +

    {t('deletePledge')}

    + +
    + +

    {t('deletePledgeMsg')}

    +
    + + + + +
    + + ); +}; +export default PledgeDeleteModal; diff --git a/src/screens/FundCampaignPledge/PledgeModal.test.tsx b/src/screens/FundCampaignPledge/PledgeModal.test.tsx new file mode 100644 index 0000000000..49c0447992 --- /dev/null +++ b/src/screens/FundCampaignPledge/PledgeModal.test.tsx @@ -0,0 +1,213 @@ +import type { ApolloLink } from '@apollo/client'; +import { MockedProvider } from '@apollo/react-testing'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import type { RenderResult } from '@testing-library/react'; +import { + cleanup, + fireEvent, + render, + screen, + waitFor, +} from '@testing-library/react'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { store } from 'state/store'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import i18nForTest from '../../utils/i18nForTest'; +import { PLEDGE_MODAL_MOCKS } from './PledgesMocks'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { toast } from 'react-toastify'; +import type { InterfacePledgeModal } from './PledgeModal'; +import PledgeModal from './PledgeModal'; +import React from 'react'; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +jest.mock('@mui/x-date-pickers/DateTimePicker', () => { + return { + DateTimePicker: jest.requireActual( + '@mui/x-date-pickers/DesktopDateTimePicker', + ).DesktopDateTimePicker, + }; +}); + +const link1 = new StaticMockLink(PLEDGE_MODAL_MOCKS); +const translations = JSON.parse( + JSON.stringify(i18nForTest.getDataByLanguage('en')?.translation.pledges), +); + +const pledgeProps: InterfacePledgeModal[] = [ + { + isOpen: true, + hide: jest.fn(), + pledge: { + _id: '1', + amount: 100, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-10', + users: [ + { + _id: '1', + firstName: 'John', + lastName: 'Doe', + image: null, + }, + ], + }, + refetchPledge: jest.fn(), + campaignId: 'campaignId', + orgId: 'orgId', + endDate: new Date(), + mode: 'create', + }, + { + isOpen: true, + hide: jest.fn(), + pledge: { + _id: '1', + amount: 100, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-10', + users: [ + { + _id: '1', + firstName: 'John', + lastName: 'Doe', + image: null, + }, + ], + }, + refetchPledge: jest.fn(), + campaignId: 'campaignId', + orgId: 'orgId', + endDate: new Date(), + mode: 'edit', + }, +]; +const renderPledgeModal = ( + link: ApolloLink, + props: InterfacePledgeModal, +): RenderResult => { + return render( + + + + + + + + + + + , + ); +}; + +describe('PledgeModal', () => { + beforeAll(() => { + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: 'orgId', fundCampaignId: 'fundCampaignId' }), + })); + }); + + afterAll(() => { + jest.clearAllMocks(); + }); + + afterEach(() => { + cleanup(); + }); + it('should populate form fields with correct values in edit mode', async () => { + renderPledgeModal(link1, pledgeProps[1]); + await waitFor(() => + expect(screen.getByText(translations.editPledge)).toBeInTheDocument(), + ); + expect(screen.getByTestId('pledgerSelect')).toHaveTextContent('John Doe'); + expect(screen.getByLabelText('Start Date')).toHaveValue('01/01/2024'); + expect(screen.getByLabelText('End Date')).toHaveValue('10/01/2024'); + expect(screen.getByLabelText('Currency')).toHaveTextContent('USD ($)'); + expect(screen.getByLabelText('Amount')).toHaveValue('100'); + }); + + it('should update pledgeAmount when input value changes', async () => { + renderPledgeModal(link1, pledgeProps[1]); + const amountInput = screen.getByLabelText('Amount'); + expect(amountInput).toHaveValue('100'); + fireEvent.change(amountInput, { target: { value: '200' } }); + expect(amountInput).toHaveValue('200'); + }); + + it('should not update pledgeAmount when input value is less than or equal to 0', async () => { + renderPledgeModal(link1, pledgeProps[1]); + const amountInput = screen.getByLabelText('Amount'); + expect(amountInput).toHaveValue('100'); + fireEvent.change(amountInput, { target: { value: '-10' } }); + expect(amountInput).toHaveValue('100'); + }); + + it('should update pledgeStartDate when a new date is selected', async () => { + renderPledgeModal(link1, pledgeProps[1]); + const startDateInput = screen.getByLabelText('Start Date'); + fireEvent.change(startDateInput, { target: { value: '02/01/2024' } }); + expect(startDateInput).toHaveValue('02/01/2024'); + expect(pledgeProps[1].pledge?.startDate).toEqual('2024-01-01'); + }); + + it('pledgeStartDate onChange when its null', async () => { + renderPledgeModal(link1, pledgeProps[1]); + const startDateInput = screen.getByLabelText('Start Date'); + fireEvent.change(startDateInput, { target: { value: null } }); + expect(pledgeProps[1].pledge?.startDate).toEqual('2024-01-01'); + }); + + it('should update pledgeEndDate when a new date is selected', async () => { + renderPledgeModal(link1, pledgeProps[1]); + const startDateInput = screen.getByLabelText('End Date'); + fireEvent.change(startDateInput, { target: { value: '02/01/2024' } }); + expect(startDateInput).toHaveValue('02/01/2024'); + expect(pledgeProps[1].pledge?.endDate).toEqual('2024-01-10'); + }); + + it('pledgeEndDate onChange when its null', async () => { + renderPledgeModal(link1, pledgeProps[1]); + const endDateInput = screen.getByLabelText('End Date'); + fireEvent.change(endDateInput, { target: { value: null } }); + expect(pledgeProps[1].pledge?.endDate).toEqual('2024-01-10'); + }); + + it('should create pledge', async () => { + renderPledgeModal(link1, pledgeProps[0]); + + fireEvent.change(screen.getByLabelText('Amount'), { + target: { value: '200' }, + }); + fireEvent.change(screen.getByLabelText('Start Date'), { + target: { value: '02/01/2024' }, + }); + fireEvent.change(screen.getByLabelText('End Date'), { + target: { value: '02/01/2024' }, + }); + + expect(screen.getByLabelText('Amount')).toHaveValue('200'); + expect(screen.getByLabelText('Start Date')).toHaveValue('02/01/2024'); + expect(screen.getByLabelText('End Date')).toHaveValue('02/01/2024'); + expect(screen.getByTestId('submitPledgeBtn')).toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('submitPledgeBtn')); + + await waitFor(() => { + expect(toast.success).toHaveBeenCalled(); + expect(pledgeProps[0].refetchPledge).toHaveBeenCalled(); + expect(pledgeProps[0].hide).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/screens/FundCampaignPledge/PledgeModal.tsx b/src/screens/FundCampaignPledge/PledgeModal.tsx new file mode 100644 index 0000000000..3e22d604a0 --- /dev/null +++ b/src/screens/FundCampaignPledge/PledgeModal.tsx @@ -0,0 +1,322 @@ +import { DatePicker } from '@mui/x-date-pickers'; +import dayjs, { type Dayjs } from 'dayjs'; +import type { ChangeEvent } from 'react'; +import { Button, Form, Modal } from 'react-bootstrap'; +import { currencyOptions, currencySymbols } from 'utils/currency'; +import type { + InterfaceCreatePledge, + InterfacePledgeInfo, + InterfacePledger, +} from 'utils/interfaces'; +import styles from './FundCampaignPledge.module.css'; +import React, { useCallback, useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useMutation, useQuery } from '@apollo/client'; +import { CREATE_PlEDGE, UPDATE_PLEDGE } from 'GraphQl/Mutations/PledgeMutation'; +import { toast } from 'react-toastify'; +import { + Autocomplete, + FormControl, + InputLabel, + MenuItem, + Select, + TextField, +} from '@mui/material'; + +import { MEMBERS_LIST } from 'GraphQl/Queries/Queries'; + +export interface InterfacePledgeModal { + isOpen: boolean; + hide: () => void; + campaignId: string; + orgId: string; + pledge: InterfacePledgeInfo | null; + refetchPledge: () => void; + endDate: Date; + mode: 'create' | 'edit'; +} +const PledgeModal: React.FC = ({ + isOpen, + hide, + campaignId, + orgId, + pledge, + refetchPledge, + endDate, + mode, +}) => { + const { t } = useTranslation('translation', { + keyPrefix: 'pledges', + }); + const { t: tCommon } = useTranslation('common'); + + const [formState, setFormState] = useState({ + pledgeUsers: [], + pledgeAmount: pledge?.amount ?? 0, + pledgeCurrency: pledge?.currency ?? 'USD', + pledgeEndDate: new Date(pledge?.endDate ?? new Date()), + pledgeStartDate: new Date(pledge?.startDate ?? new Date()), + }); + const [pledgers, setPledgers] = useState([]); + const [updatePledge] = useMutation(UPDATE_PLEDGE); + const [createPledge] = useMutation(CREATE_PlEDGE); + + const { data: memberData } = useQuery(MEMBERS_LIST, { + variables: { id: orgId }, + }); + + useEffect(() => { + setFormState({ + pledgeUsers: pledge?.users ?? [], + pledgeAmount: pledge?.amount ?? 0, + pledgeCurrency: pledge?.currency ?? 'USD', + pledgeEndDate: new Date(pledge?.endDate ?? new Date()), + pledgeStartDate: new Date(pledge?.startDate ?? new Date()), + }); + }, [pledge]); + + useEffect(() => { + if (memberData) { + /*istanbul ignore next*/ + setPledgers(memberData.organizations[0].members); + } + }, [memberData]); + + const { + pledgeUsers, + pledgeAmount, + pledgeCurrency, + pledgeStartDate, + pledgeEndDate, + } = formState; + + /*istanbul ignore next*/ + const updatePledgeHandler = useCallback( + async (e: ChangeEvent): Promise => { + e.preventDefault(); + const startDate = dayjs(pledgeStartDate).format('YYYY-MM-DD'); + const endDate = dayjs(pledgeEndDate).format('YYYY-MM-DD'); + + const updatedFields: { + [key: string]: number | string | string[] | undefined; + } = {}; + // checks if there are changes to the pledge and adds them to the updatedFields object + if (pledgeAmount !== pledge?.amount) { + updatedFields.amount = pledgeAmount; + } + if (pledgeCurrency !== pledge?.currency) { + updatedFields.currency = pledgeCurrency; + } + if (startDate !== dayjs(pledge?.startDate).format('YYYY-MM-DD')) { + updatedFields.startDate = startDate; + } + if (endDate !== dayjs(pledge?.endDate).format('YYYY-MM-DD')) { + updatedFields.endDate = endDate; + } + if (pledgeUsers !== pledge?.users) { + updatedFields.users = pledgeUsers.map((user) => user._id); + } + try { + await updatePledge({ + variables: { + id: pledge?._id, + ...updatedFields, + }, + }); + toast.success(t('pledgeUpdated')); + refetchPledge(); + hide(); + } catch (error: unknown) { + toast.error((error as Error).message); + } + }, + [formState, pledge], + ); + + // Function to create a new pledge + const createPledgeHandler = useCallback( + async (e: ChangeEvent): Promise => { + try { + e.preventDefault(); + await createPledge({ + variables: { + campaignId, + amount: pledgeAmount, + currency: pledgeCurrency, + startDate: dayjs(pledgeStartDate).format('YYYY-MM-DD'), + endDate: dayjs(pledgeEndDate).format('YYYY-MM-DD'), + userIds: pledgeUsers.map((user) => user._id), + }, + }); + + toast.success(t('pledgeCreated')); + refetchPledge(); + setFormState({ + pledgeUsers: [], + pledgeAmount: 0, + pledgeCurrency: 'USD', + pledgeEndDate: new Date(), + pledgeStartDate: new Date(), + }); + hide(); + } catch (error: unknown) { + /*istanbul ignore next*/ + toast.error((error as Error).message); + } + }, + [formState, campaignId], + ); + + return ( + + +

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

    + +
    + +
    + {/* A Multi-select dropdown enables admin to select more than one pledger for participating in a pledge */} + + option._id === value._id} + filterSelectedOptions={true} + getOptionLabel={(member: InterfacePledger): string => + `${member.firstName} ${member.lastName}` + } + onChange={ + /*istanbul ignore next*/ + (_, newPledgers): void => { + setFormState({ + ...formState, + pledgeUsers: newPledgers, + }); + } + } + renderInput={(params) => ( + + )} + /> + + + {/* Date Calendar Component to select start date of an event */} + { + if (date) { + setFormState({ + ...formState, + pledgeStartDate: date.toDate(), + pledgeEndDate: + pledgeEndDate && + /*istanbul ignore next*/ + (pledgeEndDate < date?.toDate() + ? date.toDate() + : pledgeEndDate), + }); + } + }} + minDate={dayjs(pledgeStartDate)} + maxDate={dayjs(endDate)} + /> + {/* Date Calendar Component to select end Date of an event */} + { + if (date) { + setFormState({ + ...formState, + pledgeEndDate: date.toDate(), + }); + } + }} + minDate={dayjs(pledgeStartDate)} + maxDate={dayjs(endDate)} + /> + + + {/* Dropdown to select the currency in which amount is to be pledged */} + + + {t('currency')} + + + + {/* Input field to enter amount to be pledged */} + + { + if (parseInt(e.target.value) > 0) { + setFormState({ + ...formState, + pledgeAmount: parseInt(e.target.value), + }); + } + }} + /> + + + {/* Button to submit the pledge form */} + +
    +
    +
    + ); +}; +export default PledgeModal; diff --git a/src/screens/FundCampaignPledge/PledgesMocks.ts b/src/screens/FundCampaignPledge/PledgesMocks.ts new file mode 100644 index 0000000000..71d74b1805 --- /dev/null +++ b/src/screens/FundCampaignPledge/PledgesMocks.ts @@ -0,0 +1,579 @@ +import { + CREATE_PlEDGE, + DELETE_PLEDGE, + UPDATE_PLEDGE, +} from 'GraphQl/Mutations/PledgeMutation'; +import { MEMBERS_LIST } from 'GraphQl/Queries/Queries'; +import { FUND_CAMPAIGN_PLEDGE } from 'GraphQl/Queries/fundQueries'; + +export const MOCKS = [ + { + request: { + query: FUND_CAMPAIGN_PLEDGE, + variables: { + id: 'fundCampaignId', + orderBy: 'endDate_DESC', + }, + }, + result: { + data: { + getFundraisingCampaignById: { + name: 'Campaign Name', + fundingGoal: 1000, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-08-08', + pledges: [ + { + _id: '1', + amount: 100, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-10', + users: [ + { + _id: '1', + firstName: 'John', + lastName: 'Doe', + image: 'img-url', + }, + { + _id: '2', + firstName: 'John', + lastName: 'Doe2', + image: 'img-url2', + }, + { + _id: '3', + firstName: 'John', + lastName: 'Doe3', + image: 'img-url3', + }, + { + _id: '4', + firstName: 'John', + lastName: 'Doe4', + image: 'img-url4', + }, + { + _id: '5', + firstName: 'John', + lastName: 'Doe5', + image: 'img-url5', + }, + { + _id: '6', + firstName: 'John', + lastName: 'Doe6', + image: 'img-url6', + }, + { + _id: '7', + firstName: 'John', + lastName: 'Doe7', + image: 'img-url7', + }, + { + _id: '8', + firstName: 'John', + lastName: 'Doe8', + image: 'img-url8', + }, + { + _id: '9', + firstName: 'John', + lastName: 'Doe9', + image: 'img-url9', + }, + { + _id: '10', + firstName: 'John', + lastName: 'Doe10', + image: null, + }, + ], + }, + { + _id: '2', + amount: 200, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-09', + users: [ + { + _id: '2', + firstName: 'Jane', + lastName: 'Doe', + image: null, + }, + ], + }, + ], + }, + }, + }, + }, + { + request: { + query: FUND_CAMPAIGN_PLEDGE, + variables: { + id: 'fundCampaignId', + orderBy: 'endDate_ASC', + }, + }, + result: { + data: { + getFundraisingCampaignById: { + name: 'Campaign Name', + fundingGoal: 1000, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-08-08', + pledges: [ + { + _id: '2', + amount: 200, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-09', + users: [ + { + _id: '2', + firstName: 'Jane', + lastName: 'Doe', + image: null, + }, + ], + }, + { + _id: '1', + amount: 100, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-10', + users: [ + { + _id: '1', + firstName: 'John', + lastName: 'Doe', + image: null, + }, + ], + }, + ], + }, + }, + }, + }, + { + request: { + query: FUND_CAMPAIGN_PLEDGE, + variables: { + id: 'fundCampaignId', + orderBy: 'amount_DESC', + }, + }, + result: { + data: { + getFundraisingCampaignById: { + name: 'Campaign Name', + fundingGoal: 1000, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-08-08', + pledges: [ + { + _id: '2', + amount: 200, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-09', + users: [ + { + _id: '2', + firstName: 'Jane', + lastName: 'Doe', + image: null, + }, + ], + }, + { + _id: '1', + amount: 100, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-10', + users: [ + { + _id: '1', + firstName: 'John', + lastName: 'Doe', + image: null, + }, + ], + }, + ], + }, + }, + }, + }, + { + request: { + query: FUND_CAMPAIGN_PLEDGE, + variables: { + id: 'fundCampaignId', + orderBy: 'amount_ASC', + }, + }, + result: { + data: { + getFundraisingCampaignById: { + name: 'Campaign Name', + fundingGoal: 1000, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-08-08', + pledges: [ + { + _id: '1', + amount: 100, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-10', + users: [ + { + _id: '1', + firstName: 'John', + lastName: 'Doe', + image: null, + }, + ], + }, + { + _id: '2', + amount: 200, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-09', + users: [ + { + _id: '2', + firstName: 'Jane', + lastName: 'Doe', + image: null, + }, + ], + }, + ], + }, + }, + }, + }, + { + request: { + query: DELETE_PLEDGE, + variables: { + id: '1', + }, + }, + result: { + data: { + removeFundraisingCampaignPledge: { + _id: '1', + }, + }, + }, + }, +]; + +export const MOCKS_FUND_CAMPAIGN_PLEDGE_ERROR = [ + { + request: { + query: FUND_CAMPAIGN_PLEDGE, + variables: { + id: 'fundCampaignId', + orderBy: 'endDate_DESC', + }, + }, + error: new Error('Error fetching pledges'), + }, +]; + +export const MOCKS_CREATE_PLEDGE_ERROR = [ + { + request: { + query: FUND_CAMPAIGN_PLEDGE, + variables: { + id: undefined, + }, + }, + result: { + data: { + getFundraisingCampaignById: { + startDate: '2024-01-01', + endDate: '2024-01-01', + pledges: [ + { + _id: '1', + amount: 100, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-01', + users: [ + { + _id: '1', + firstName: 'John', + }, + ], + }, + { + _id: '2', + amount: 200, + currency: 'USD', + startDate: '2024-03-03', + endDate: '2024-04-03', + users: [ + { + _id: '2', + firstName: 'Jane', + }, + ], + }, + ], + }, + }, + }, + }, + { + request: { + query: CREATE_PlEDGE, + variables: { + campaignId: 'campaignId', + amount: 200, + currency: 'USD', + startDate: '2024-01-02', + endDate: '2024-01-02', + userIds: ['1'], + }, + }, + error: new Error('Error creating pledge'), + }, +]; + +export const MOCKS_UPDATE_PLEDGE_ERROR = [ + { + request: { + query: FUND_CAMPAIGN_PLEDGE, + variables: { + id: undefined, + }, + }, + result: { + data: { + getFundraisingCampaignById: { + startDate: '2024-01-01', + endDate: '2024-01-01', + pledges: [ + { + _id: '1', + amount: 100, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-01', + users: [ + { + _id: '1', + firstName: 'John', + }, + ], + }, + { + _id: '2', + amount: 200, + currency: 'USD', + startDate: '2024-03-03', + endDate: '2024-04-03', + users: [ + { + _id: '2', + firstName: 'Jane', + }, + ], + }, + ], + }, + }, + }, + }, + { + request: { + query: UPDATE_PLEDGE, + variables: { + id: '1', + amount: 200, + currency: 'USD', + startDate: '2024-03-10', + endDate: '2024-03-10', + }, + }, + error: new Error('Error updating pledge'), + }, +]; + +export const MOCKS_DELETE_PLEDGE_ERROR = [ + { + request: { + query: FUND_CAMPAIGN_PLEDGE, + variables: { + id: undefined, + }, + }, + result: { + data: { + getFundraisingCampaignById: { + startDate: '2024-01-01', + endDate: '2024-01-01', + pledges: [ + { + _id: '1', + amount: 100, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-01', + users: [ + { + _id: '1', + firstName: 'John', + }, + ], + }, + { + _id: '2', + amount: 200, + currency: 'USD', + startDate: '2024-03-03', + endDate: '2024-04-03', + users: [ + { + _id: '2', + firstName: 'Jane', + }, + ], + }, + ], + }, + }, + }, + }, + { + request: { + query: DELETE_PLEDGE, + variables: { + id: '1', + }, + }, + error: new Error('Error deleting pledge'), + }, +]; + +export const EMPTY_MOCKS = [ + { + request: { + query: FUND_CAMPAIGN_PLEDGE, + variables: { + id: 'fundCampaignId', + orderBy: 'endDate_DESC', + }, + }, + result: { + data: { + getFundraisingCampaignById: { + name: 'Campaign Name', + fundingGoal: 1000, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-01', + pledges: [], + }, + }, + }, + }, +]; + +export const PLEDGE_MODAL_MOCKS = [ + { + request: { + query: MEMBERS_LIST, + variables: { + id: 'orgId', + }, + }, + result: { + data: { + organizations: [ + { + _id: 'orgId', + members: [ + { + createdAt: '2023-04-13T04:53:17.742Z', + email: 'testuser4@example.com', + firstName: 'John', + image: 'img-url', + lastName: 'Doe', + organizationsBlockedBy: [], + __typename: 'User', + _id: '1', + }, + { + createdAt: '2024-04-13T04:53:17.742Z', + email: 'testuser2@example.com', + firstName: 'Anna', + image: null, + lastName: 'Bradley', + organizationsBlockedBy: [], + __typename: 'User', + _id: '2', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: UPDATE_PLEDGE, + variables: { + id: '1', + amount: 200, + }, + }, + result: { + data: { + updateFundraisingCampaignPledge: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: CREATE_PlEDGE, + variables: { + campaignId: 'campaignId', + amount: 200, + currency: 'USD', + startDate: '2024-01-02', + endDate: '2024-01-02', + userIds: ['1'], + }, + }, + result: { + data: { + createFundraisingCampaignPledge: { + _id: '3', + }, + }, + }, + }, +]; diff --git a/src/screens/LoginPage/LoginPage.module.css b/src/screens/LoginPage/LoginPage.module.css new file mode 100644 index 0000000000..e7ce0eca7e --- /dev/null +++ b/src/screens/LoginPage/LoginPage.module.css @@ -0,0 +1,235 @@ +.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.test.tsx new file mode 100644 index 0000000000..a61f8adb2e --- /dev/null +++ b/src/screens/LoginPage/LoginPage.test.tsx @@ -0,0 +1,1003 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { act, render, screen, fireEvent, within } from '@testing-library/react'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import userEvent from '@testing-library/user-event'; +import { I18nextProvider } from 'react-i18next'; +import 'jest-localstorage-mock'; +import 'jest-location-mock'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import LoginPage from './LoginPage'; +import { + LOGIN_MUTATION, + RECAPTCHA_MUTATION, + SIGNUP_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import { store } from 'state/store'; +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'; + +const MOCKS = [ + { + request: { + query: LOGIN_MUTATION, + variables: { + email: 'johndoe@gmail.com', + password: 'johndoe', + }, + }, + result: { + data: { + login: { + user: { + _id: '1', + }, + appUserProfile: { + isSuperAdmin: false, + adminFor: ['123', '456'], + }, + accessToken: 'accessToken', + refreshToken: 'refreshToken', + }, + }, + }, + }, + { + request: { + query: SIGNUP_MUTATION, + variables: { + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@gmail.com', + password: 'johnDoe', + }, + }, + result: { + data: { + register: { + user: { + _id: '1', + }, + accessToken: 'accessToken', + refreshToken: 'refreshToken', + }, + }, + }, + }, + { + request: { + query: RECAPTCHA_MUTATION, + variables: { + recaptchaToken: null, + }, + }, + result: { + data: { + recaptcha: true, + }, + }, + }, + { + request: { + query: GET_COMMUNITY_DATA, + }, + result: { + data: { + getCommunityData: null, + }, + }, + }, +]; + +const MOCKS2 = [ + { + request: { + query: GET_COMMUNITY_DATA, + }, + result: { + data: { + getCommunityData: { + _id: 'communitId', + websiteLink: 'http://link.com', + name: 'testName', + logoUrl: 'image.png', + __typename: 'Community', + socialMediaUrls: { + facebook: 'http://url.com', + gitHub: 'http://url.com', + youTube: 'http://url.com', + instagram: 'http://url.com', + linkedIn: 'http://url.com', + reddit: 'http://url.com', + slack: 'http://url.com', + twitter: null, + __typename: 'SocialMediaUrls', + }, + }, + }, + }, + }, +]; +const MOCKS3 = [ + { + request: { + query: ORGANIZATION_LIST, + }, + result: { + data: { + organizations: [ + { + _id: '6437904485008f171cf29924', + image: null, + creator: { + firstName: 'Wilt', + lastName: 'Shepherd', + }, + name: 'Unity Foundation', + members: [ + { + _id: '64378abd85008f171cf2990d', + }, + ], + admins: [ + { + _id: '64378abd85008f171cf2990d', + }, + ], + createdAt: '2023-04-13T05:16:52.827Z', + address: { + city: 'Bronx', + countryCode: 'US', + dependentLocality: 'Some Dependent Locality', + line1: '123 Random Street', + line2: 'Apartment 456', + postalCode: '10451', + sortingCode: 'ABC-123', + state: 'NYC', + }, + }, + { + _id: 'db1d5caad2ade57ab811e681', + image: null, + creator: { + firstName: 'Sonya', + lastName: 'Jones', + }, + name: 'Mills Group', + members: [ + { + _id: '661b8410bd25a325da05e67c', + }, + ], + admins: [ + { + _id: '661b8410bd25a325da05e67c', + }, + ], + createdAt: '2024-04-14T07:21:52.940Z', + address: { + city: 'Lake Martineside', + countryCode: 'SL', + dependentLocality: 'Apt. 544', + line1: '5112 Dare Centers', + line2: 'Suite 163', + postalCode: '10452', + sortingCode: '46565-3458', + state: 'New Hampshire', + }, + }, + ], + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(MOCKS2, true); +const link3 = new StaticMockLink(MOCKS3, true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }, +})); + +jest.mock('Constant/constant.ts', () => ({ + ...jest.requireActual('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'), + useNavigate: () => mockNavigate, +})); + +jest.mock('react-google-recaptcha', () => { + const react = jest.requireActual('react'); + const recaptcha = react.forwardRef( + ( + props: { + onChange: (value: string) => void; + } & React.InputHTMLAttributes, + ref: React.LegacyRef | undefined, + ): JSX.Element => { + const { onChange, ...otherProps } = props; + + const handleChange = ( + event: React.ChangeEvent, + ): void => { + if (onChange) { + onChange(event.target.value); + } + }; + + return ( + <> + + + ); + }, + ); + return recaptcha; +}); + +describe('Testing Login Page Screen', () => { + test('Component Should be rendered properly', async () => { + window.location.assign('/orglist'); + + render( + + + + + + + + + , + ); + + await wait(); + const adminLink = screen.getByText(/Admin/i); + userEvent.click(adminLink); + await wait(); + expect(screen.getByText(/Admin/i)).toBeInTheDocument(); + expect(window.location).toBeAt('/orglist'); + }); + + test('There should be default values of pre-login data when queried result is null', async () => { + render( + + + + + + + + + , + ); + await wait(); + + expect(screen.getByTestId('PalisadoesLogo')).toBeInTheDocument(); + expect( + screen.getAllByTestId('PalisadoesSocialMedia')[0], + ).toBeInTheDocument(); + + await wait(); + expect(screen.queryByTestId('preLoginLogo')).not.toBeInTheDocument(); + 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 () => { + render( + + + + + + + + + , + ); + await wait(); + expect(screen.getByTestId('preLoginLogo')).toBeInTheDocument(); + expect(screen.getAllByTestId('preLoginSocialMedia')[0]).toBeInTheDocument(); + + await wait(); + expect(screen.queryByTestId('PalisadoesLogo')).not.toBeInTheDocument(); + expect(screen.queryAllByTestId('PalisadoesSocialMedia')[0]).toBeUndefined(); + }); + + test('Testing registration functionality', async () => { + const formData = { + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@gmail.com', + password: 'John@123', + confirmPassword: 'John@123', + }; + + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId(/goToRegisterPortion/i)); + + await wait(); + + 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')); + }); + + test('Testing registration functionality when all inputs are invalid', async () => { + const formData = { + firstName: '1234', + lastName: '8890', + email: 'j@l.co', + password: 'john@123', + confirmPassword: 'john@123', + }; + + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId(/goToRegisterPortion/i)); + + await wait(); + + 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')); + }); + + test('Testing registration functionality, when password and confirm password is not same', async () => { + const formData = { + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@gmail.com', + password: 'johnDoe@1', + confirmPassword: 'doeJohn@2', + }; + + 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')); + }); + + test('Testing registration functionality, when input is not filled correctly', async () => { + const formData = { + firstName: 'J', + lastName: 'D', + email: 'johndoe@gmail.com', + password: 'joe', + confirmPassword: 'joe', + }; + + 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')); + }); + + test('switches to login tab on successful registration', async () => { + const formData = { + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@gmail.com', + password: 'johndoe', + confirmPassword: 'johndoe', + }; + + 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 wait(); + + // Check if the login tab is now active by checking for elements that only appear in the login tab + expect(screen.getByTestId('loginBtn')).toBeInTheDocument(); + expect(screen.getByTestId('goToRegisterPortion')).toBeInTheDocument(); + }); + + test('Testing toggle login register portion', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('goToRegisterPortion')); + + userEvent.click(screen.getByTestId('goToLoginPortion')); + + await wait(); + }); + + test('Testing login functionality', async () => { + const formData = { + email: 'johndoe@gmail.com', + password: 'johndoe', + }; + + 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 wait(); + }); + + test('Testing password preview feature for login', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + const input = screen.getByTestId('password') as HTMLInputElement; + const toggleText = screen.getByTestId('showLoginPassword'); + // password should be hidden + expect(input.type).toBe('password'); + // click the toggle button to show password + userEvent.click(toggleText); + expect(input.type).toBe('text'); + // click the toggle button to hide password + userEvent.click(toggleText); + expect(input.type).toBe('password'); + + await wait(); + }); + + test('Testing password preview feature for register', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('goToRegisterPortion')); + + const input = screen.getByTestId('passwordField') as HTMLInputElement; + const toggleText = screen.getByTestId('showPassword'); + // password should be hidden + expect(input.type).toBe('password'); + // click the toggle button to show password + userEvent.click(toggleText); + expect(input.type).toBe('text'); + // click the toggle button to hide password + userEvent.click(toggleText); + expect(input.type).toBe('password'); + + await wait(); + }); + + test('Testing confirm password preview feature', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('goToRegisterPortion')); + + const input = screen.getByTestId('cpassword') as HTMLInputElement; + const toggleText = screen.getByTestId('showPasswordCon'); + // password should be hidden + expect(input.type).toBe('password'); + // click the toggle button to show password + userEvent.click(toggleText); + expect(input.type).toBe('text'); + // click the toggle button to hide password + userEvent.click(toggleText); + expect(input.type).toBe('password'); + + await wait(); + }); + + test('Testing for the password error warning when user firsts lands on a page', async () => { + render( + + + + + + + + + , + ); + await wait(); + + 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 () => { + const password = { + password: '7', + }; + + render( + + + + + + + + + , + ); + await wait(); + + userEvent.click(screen.getByTestId('goToRegisterPortion')); + + userEvent.type(screen.getByPlaceholderText('Password'), password.password); + + expect(screen.getByTestId('passwordField')).toHaveFocus(); + + expect(password.password.length).toBeLessThan(8); + + 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 () => { + const password = { + password: '12345678', + }; + + render( + + + + + + + + + , + ); + await wait(); + + userEvent.click(screen.getByTestId('goToRegisterPortion')); + + userEvent.type(screen.getByPlaceholderText('Password'), password.password); + + expect(screen.getByTestId('passwordField')).toHaveFocus(); + + expect(password.password.length).toBeGreaterThanOrEqual(8); + + 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 () => { + const password = { + password: '7', + }; + + render( + + + + + + + + + , + ); + await wait(); + + userEvent.click(screen.getByTestId('goToRegisterPortion')); + + expect(screen.getByPlaceholderText('Password')).not.toHaveFocus(); + + userEvent.type(screen.getByPlaceholderText('Password'), password.password); + + expect(password.password.length).toBeLessThan(8); + + 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 () => { + const password = { + password: '12345678', + }; + + render( + + + + + + + + + , + ); + await wait(); + + userEvent.click(screen.getByTestId('goToRegisterPortion')); + + await wait(); + + expect(screen.getByPlaceholderText('Password')).not.toHaveFocus(); + + userEvent.type(screen.getByPlaceholderText('Password'), password.password); + + expect(password.password.length).toBeGreaterThanOrEqual(8); + + expect(screen.queryByTestId('passwordCheck')).toBeNull(); + }); + + test('Component Should be rendered properly for user login', async () => { + window.location.assign('/user/organizations'); + + render( + + + + + + + + + , + ); + + await wait(); + const userLink = screen.getByText(/User/i); + userEvent.click(userLink); + await wait(); + expect(screen.getByText(/User Login/i)).toBeInTheDocument(); + expect(window.location).toBeAt('/user/organizations'); + }); + + test('on value change of ReCAPTCHA onChange event should be triggered in both the captcha', async () => { + render( + + + + + + + + + , + ); + await wait(); + + const recaptchaElements = screen.getAllByTestId('mock-recaptcha'); + + for (const recaptchaElement of recaptchaElements) { + const inputElement = recaptchaElement as HTMLInputElement; + + fireEvent.input(inputElement, { + target: { value: 'test-token' }, + }); + + fireEvent.change(inputElement, { + target: { value: 'test-token2' }, + }); + + expect(recaptchaElement).toHaveValue('test-token2'); + } + }); +}); + +describe('Testing redirect if already logged in', () => { + test('Logged in as USER', async () => { + const { setItem } = useLocalStorage(); + setItem('IsLoggedIn', 'TRUE'); + setItem('userId', 'id'); + render( + + + + + + + + + , + ); + await wait(); + expect(mockNavigate).toHaveBeenCalledWith('/user/organizations'); + }); + test('Logged in as Admin or SuperAdmin', async () => { + const { setItem } = useLocalStorage(); + setItem('IsLoggedIn', 'TRUE'); + setItem('userId', null); + render( + + + + + + + + + , + ); + await wait(); + expect(mockNavigate).toHaveBeenCalledWith('/orglist'); + }); +}); +test('Render the Select Organization list and change the option', async () => { + render( + + + + + + + + + , + ); + + await wait(); + userEvent.click(screen.getByTestId(/goToRegisterPortion/i)); + await wait(); + const autocomplete = screen.getByTestId('selectOrg'); + const input = within(autocomplete).getByRole('combobox'); + autocomplete.focus(); + // the value here can be any string you want, so you may also consider to + // wrapper it as a function and pass in inputValue as parameter + 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(); + }); + + test('Checks if Talawa-API resource is loaded successfully', async () => { + global.fetch = jest.fn(() => Promise.resolve({} as unknown as Response)); + + await act(async () => { + render( + + + + + + + + + , + ); + }); + + expect(fetch).toHaveBeenCalledWith(BACKEND_URL); + }); + + test('displays warning message when resource loading fails', async () => { + const mockError = new Error('Network error'); + global.fetch = jest.fn(() => Promise.reject(mockError)); + + await act(async () => { + render( + + + + + + + + + , + ); + }); + + expect(fetch).toHaveBeenCalledWith(BACKEND_URL); + }); +}); diff --git a/src/screens/LoginPage/LoginPage.tsx b/src/screens/LoginPage/LoginPage.tsx new file mode 100644 index 0000000000..24b247e427 --- /dev/null +++ b/src/screens/LoginPage/LoginPage.tsx @@ -0,0 +1,877 @@ +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 { Form } from 'react-bootstrap'; +import Button from 'react-bootstrap/Button'; +import Col from 'react-bootstrap/Col'; +import Row from 'react-bootstrap/Row'; +import ReCAPTCHA from 'react-google-recaptcha'; +import { useTranslation } from 'react-i18next'; +import { Link, useNavigate } from 'react-router-dom'; +import { toast } from 'react-toastify'; + +import EmailOutlinedIcon from '@mui/icons-material/EmailOutlined'; +import { + BACKEND_URL, + REACT_APP_USE_RECAPTCHA, + RECAPTCHA_SITE_KEY, +} from 'Constant/constant'; +import { + LOGIN_MUTATION, + RECAPTCHA_MUTATION, + SIGNUP_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import { GET_COMMUNITY_DATA, ORGANIZATION_LIST } from 'GraphQl/Queries/Queries'; +import { ReactComponent as PalisadoesLogo } from 'assets/svgs/palisadoes.svg'; +import { ReactComponent as TalawaLogo } from 'assets/svgs/talawa.svg'; +import ChangeLanguageDropDown from 'components/ChangeLanguageDropdown/ChangeLanguageDropDown'; +import Loader from 'components/Loader/Loader'; +import LoginPortalToggle from 'components/LoginPortalToggle/LoginPortalToggle'; +import { errorHandler } from 'utils/errorHandler'; +import useLocalStorage from 'utils/useLocalstorage'; +import { socialMediaLinks } from '../../constants'; +import styles from './LoginPage.module.css'; +import type { InterfaceQueryOrganizationListObject } from 'utils/interfaces'; +import { Autocomplete, TextField } from '@mui/material'; +import i18n from 'utils/i18n'; + +const loginPage = (): JSX.Element => { + const { t } = useTranslation('translation', { keyPrefix: 'loginPage' }); + const { t: tCommon } = useTranslation('common'); + const { t: tErrors } = useTranslation('errors'); + + const navigate = useNavigate(); + + const { getItem, setItem } = useLocalStorage(); + + document.title = t('title'); + + type PasswordValidation = { + lowercaseChar: boolean; + uppercaseChar: boolean; + numericValue: boolean; + specialChar: boolean; + }; + + const [recaptchaToken, setRecaptchaToken] = useState(null); + const [showTab, setShowTab] = useState<'LOGIN' | 'REGISTER'>('LOGIN'); + const [role, setRole] = useState<'admin' | 'user'>('admin'); + const [componentLoader, setComponentLoader] = useState(true); + const [isInputFocused, setIsInputFocused] = useState(false); + const [signformState, setSignFormState] = useState({ + signfirstName: '', + signlastName: '', + signEmail: '', + signPassword: '', + cPassword: '', + signOrg: '', + }); + const [formState, setFormState] = useState({ + email: '', + password: '', + }); + const [showPassword, setShowPassword] = useState(false); + const [showConfirmPassword, setShowConfirmPassword] = + useState(false); + const [showAlert, setShowAlert] = useState({ + lowercaseChar: true, + uppercaseChar: true, + numericValue: true, + specialChar: true, + }); + const [organizations, setOrganizations] = useState([]); + + const passwordValidationRegExp = { + lowercaseCharRegExp: new RegExp('[a-z]'), + uppercaseCharRegExp: new RegExp('[A-Z]'), + numericalValueRegExp: new RegExp('\\d'), + specialCharRegExp: new RegExp('[!@#$%^&*()_+{}\\[\\]:;<>,.?~\\\\/-]'), + }; + + const handlePasswordCheck = (pass: string): void => { + setShowAlert({ + lowercaseChar: !passwordValidationRegExp.lowercaseCharRegExp.test(pass), + uppercaseChar: !passwordValidationRegExp.uppercaseCharRegExp.test(pass), + numericValue: !passwordValidationRegExp.numericalValueRegExp.test(pass), + specialChar: !passwordValidationRegExp.specialCharRegExp.test(pass), + }); + }; + + const handleRoleToggle = (role: 'admin' | 'user'): void => { + setRole(role); + }; + + useEffect(() => { + const isLoggedIn = getItem('IsLoggedIn'); + if (isLoggedIn == 'TRUE') { + navigate(getItem('userId') !== null ? '/user/organizations' : '/orglist'); + } + setComponentLoader(false); + }, []); + + const togglePassword = (): void => setShowPassword(!showPassword); + const toggleConfirmPassword = (): void => + setShowConfirmPassword(!showConfirmPassword); + + const { data, loading, refetch } = useQuery(GET_COMMUNITY_DATA); + useEffect(() => { + // refetching the data if the pre-login data updates + refetch(); + }, [data]); + const [login, { loading: loginLoading }] = useMutation(LOGIN_MUTATION); + const [signup, { loading: signinLoading }] = useMutation(SIGNUP_MUTATION); + const [recaptcha, { loading: recaptchaLoading }] = + useMutation(RECAPTCHA_MUTATION); + const { data: orgData } = useQuery(ORGANIZATION_LIST); + + useEffect(() => { + if (orgData) { + const options = orgData.organizations.map( + (org: InterfaceQueryOrganizationListObject) => { + const tempObj: { label: string; id: string } | null = {} as { + label: string; + id: string; + }; + tempObj['label'] = + `${org.name}(${org.address?.city},${org.address?.state},${org.address?.countryCode})`; + tempObj['id'] = org._id; + return tempObj; + }, + ); + setOrganizations(options); + } + }, [orgData]); + + useEffect(() => { + async function loadResource(): Promise { + try { + await fetch(BACKEND_URL as string); + } catch (error) { + /* istanbul ignore next */ + errorHandler(t, error); + } + } + + loadResource(); + }, []); + + const verifyRecaptcha = async ( + recaptchaToken: string | null, + ): Promise => { + try { + /* istanbul ignore next */ + if (REACT_APP_USE_RECAPTCHA !== 'yes') { + return true; + } + const { data } = await recaptcha({ + variables: { + recaptchaToken, + }, + }); + + return data.recaptcha; + } catch (error) { + /* istanbul ignore next */ + toast.error(t('captchaError')); + } + }; + + const handleCaptcha = (token: string | null): void => { + setRecaptchaToken(token); + }; + + const signupLink = async (e: ChangeEvent): Promise => { + e.preventDefault(); + + const { + signfirstName, + signlastName, + signEmail, + signPassword, + cPassword, + signOrg, + } = signformState; + + const isVerified = await verifyRecaptcha(recaptchaToken); + /* istanbul ignore next */ + if (!isVerified) { + toast.error(t('Please_check_the_captcha')); + return; + } + const isValidatedString = (value: string): boolean => + /^[a-zA-Z]+$/.test(value); + + const validatePassword = (password: string): boolean => { + const lengthCheck = new RegExp('^.{6,}$'); + return ( + lengthCheck.test(password) && + passwordValidationRegExp.lowercaseCharRegExp.test(password) && + passwordValidationRegExp.uppercaseCharRegExp.test(password) && + passwordValidationRegExp.numericalValueRegExp.test(password) && + passwordValidationRegExp.specialCharRegExp.test(password) + ); + }; + + if ( + isValidatedString(signfirstName) && + isValidatedString(signlastName) && + signfirstName.length > 1 && + signlastName.length > 1 && + signEmail.length >= 8 && + signPassword.length > 1 && + validatePassword(signPassword) + ) { + if (cPassword == signPassword) { + try { + const { data: signUpData } = await signup({ + variables: { + firstName: signfirstName, + lastName: signlastName, + email: signEmail, + password: signPassword, + orgId: signOrg, + }, + }); + + /* istanbul ignore next */ + if (signUpData) { + toast.success( + t(role === 'admin' ? 'successfullyRegistered' : 'afterRegister'), + ); + setShowTab('LOGIN'); + setSignFormState({ + signfirstName: '', + signlastName: '', + signEmail: '', + signPassword: '', + cPassword: '', + signOrg: '', + }); + } + } catch (error) { + /* istanbul ignore next */ + errorHandler(t, error); + } + } else { + toast.warn(t('passwordMismatches')); + } + } else { + if (!isValidatedString(signfirstName)) { + toast.warn(t('firstName_invalid')); + } + if (!isValidatedString(signlastName)) { + toast.warn(t('lastName_invalid')); + } + if (!validatePassword(signPassword)) { + toast.warn(t('password_invalid')); + } + if (signEmail.length < 8) { + toast.warn(t('email_invalid')); + } + } + }; + + 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')); + return; + } + + try { + const { data: loginData } = await login({ + variables: { + email: formState.email, + password: formState.password, + }, + }); + + /* istanbul ignore next */ + if (loginData) { + i18n.changeLanguage(loginData.login.appUserProfile.appLanguageCode); + const { login } = loginData; + const { user, appUserProfile } = login; + const isAdmin: boolean = + appUserProfile.isSuperAdmin || appUserProfile.adminFor.length !== 0; + + if (role === 'admin' && !isAdmin) { + toast.warn(tErrors('notAuthorised')); + return; + } + const loggedInUserId = user._id; + + setItem('token', login.accessToken); + setItem('refreshToken', login.refreshToken); + setItem('IsLoggedIn', 'TRUE'); + setItem('name', `${user.firstName} ${user.lastName}`); + setItem('email', user.email); + setItem('FirstName', user.firstName); + setItem('LastName', user.lastName); + setItem('UserImage', user.image); + + if (role === 'admin') { + setItem('id', loggedInUserId); + setItem('SuperAdmin', appUserProfile.isSuperAdmin); + setItem('AdminFor', appUserProfile.adminFor); + } else { + setItem('userId', loggedInUserId); + } + + navigate(role === 'admin' ? '/orglist' : '/user/organizations'); + } else { + toast.warn(tErrors('notFound')); + } + } catch (error) { + /* istanbul ignore next */ + errorHandler(t, error); + } + }; + + if ( + componentLoader || + loginLoading || + signinLoading || + recaptchaLoading || + loading + ) { + return ; + } + const socialIconsList = socialMediaLinks.map(({ href, logo, tag }, index) => + data?.getCommunityData ? ( + data.getCommunityData?.socialMediaUrls?.[tag] && ( + + + + ) + ) : ( + + + + ), + ); + + return ( + <> +
    + + +
    + {data?.getCommunityData ? ( + + Community Logo +

    {data.getCommunityData.name}

    +
    + ) : ( + + +

    {t('fromPalisadoes')}

    +
    + )} +
    +
    {socialIconsList}
    + + +
    + + + + + + {/* LOGIN FORM */} +
    +
    +

    + {role === 'admin' ? tCommon('login') : t('userLogin')} +

    + {tCommon('email')} +
    + { + setFormState({ + ...formState, + email: e.target.value, + }); + }} + autoComplete="username" + data-testid="loginEmail" + /> + +
    + + {tCommon('password')} + +
    + { + setFormState({ + ...formState, + password: e.target.value, + }); + }} + autoComplete="current-password" + /> + +
    +
    + + {tCommon('forgotPassword')} + +
    + {REACT_APP_USE_RECAPTCHA === 'yes' ? ( +
    + +
    + ) : ( + /* istanbul ignore next */ + <> + )} + +
    +
    + {tCommon('OR')} +
    + +
    +
    + {/* REGISTER FORM */} +
    +
    +

    + {tCommon('register')} +

    + + +
    + {tCommon('firstName')} + { + setSignFormState({ + ...signformState, + signfirstName: e.target.value, + }); + }} + /> +
    + + +
    + {tCommon('lastName')} + { + setSignFormState({ + ...signformState, + signlastName: e.target.value, + }); + }} + /> +
    + +
    +
    + {tCommon('email')} +
    + { + setSignFormState({ + ...signformState, + signEmail: e.target.value.toLowerCase(), + }); + }} + /> + +
    +
    + +
    + {tCommon('password')} +
    + setIsInputFocused(true)} + onBlur={(): void => setIsInputFocused(false)} + required + value={signformState.signPassword} + onChange={(e): void => { + setSignFormState({ + ...signformState, + signPassword: e.target.value, + }); + handlePasswordCheck(e.target.value); + }} + /> + +
    +
    + {isInputFocused ? ( + signformState.signPassword.length < 6 ? ( +
    +

    + + + + {t('atleast_6_char_long')} +

    +
    + ) : ( +

    + + + + {t('atleast_6_char_long')} +

    + ) + ) : null} + + {!isInputFocused && + signformState.signPassword.length > 0 && + signformState.signPassword.length < 6 && ( +
    + + + + {t('atleast_6_char_long')} +
    + )} + {isInputFocused && ( +

    + {showAlert.lowercaseChar ? ( + + + + ) : ( + + + + )} + {t('lowercase_check')} +

    + )} + {isInputFocused && ( +

    + {showAlert.uppercaseChar ? ( + + + + ) : ( + + + + )} + {t('uppercase_check')} +

    + )} + {isInputFocused && ( +

    + {showAlert.numericValue ? ( + + + + ) : ( + + + + )} + {t('numeric_value_check')} +

    + )} + {isInputFocused && ( +

    + {showAlert.specialChar ? ( + + + + ) : ( + + + + )} + {t('special_char_check')} +

    + )} +
    +
    +
    + {tCommon('confirmPassword')} +
    + { + setSignFormState({ + ...signformState, + cPassword: e.target.value, + }); + }} + data-testid="cpassword" + autoComplete="new-password" + /> + +
    + {signformState.cPassword.length > 0 && + signformState.signPassword !== + signformState.cPassword && ( +
    + {t('Password_and_Confirm_password_mismatches.')} +
    + )} +
    +
    + {t('selectOrg')} +
    + { + setSignFormState({ + ...signformState, + signOrg: value?.id ?? '', + }); + }} + options={organizations} + renderInput={(params) => ( + + )} + /> +
    +
    + {REACT_APP_USE_RECAPTCHA === 'yes' ? ( +
    + +
    + ) : ( + /* istanbul ignore next */ + <> + )} + +
    +
    + {tCommon('OR')} +
    + +
    +
    +
    + +
    +
    + + ); +}; + +export default loginPage; diff --git a/src/screens/MemberDetail/MemberDetail.module.css b/src/screens/MemberDetail/MemberDetail.module.css new file mode 100644 index 0000000000..603e55d1d9 --- /dev/null +++ b/src/screens/MemberDetail/MemberDetail.module.css @@ -0,0 +1,523 @@ +.mainpage { + display: flex; + flex-direction: row; +} + +.sidebar { + z-index: 0; + padding-top: 5px; + margin: 0; + height: 100%; +} + +.sidebar:after { + content: ''; + background-color: #f7f7f7; + position: absolute; + width: 2px; + height: 600px; + top: 10px; + left: 94%; + display: block; +} + +.sidebarsticky { + padding: 0 2rem; + text-overflow: ellipsis; + /* overflow-x: hidden; */ +} + +/* .sidebarsticky:hover{ + overflow-x:visible; + transition: all 0.4s ease; + background-color: #707070; + +} */ +.sidebarsticky > p { + margin-top: -10px; +} + +.navitem { + padding-left: 27%; + padding-top: 12px; + padding-bottom: 12px; + cursor: pointer; +} + +.searchtitle { + color: #707070; + font-weight: 600; + font-size: 18px; + margin-top: 60px; + margin-bottom: 20px; + padding-bottom: 5px; + border-bottom: 3px solid #31bb6b; + width: 60%; +} + +.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; +} + +.logintitle { + color: #707070; + font-weight: 600; + font-size: 20px; + margin-bottom: 30px; + padding-bottom: 5px; + border-bottom: 3px solid #31bb6b; + width: 30%; +} + +.logintitleadmin { + color: #707070; + font-weight: 600; + font-size: 20px; + margin-top: 50px; + margin-bottom: 40px; + 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; + 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) { + .justifysp { + padding-left: 55px; + display: flex; + justify-content: space-evenly; + } + + .mainpageright { + width: 100%; + } + + .invitebtn { + position: relative; + right: 15px; + } +} + +.invitebtn { + 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; + background-color: #31bb6b; + 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: #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; +} + +.titlemodal { + color: #707070; + font-weight: 600; + font-size: 20px; + margin-bottom: 20px; + padding-bottom: 5px; + border-bottom: 3px solid #31bb6b; + 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; +} + +.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%; +} + +.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); + } +} + +.list_box { + 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; +} + +.checkboxdiv { + display: flex; +} + +.checkboxdiv > 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%; + } + + .searchtitle { + margin-top: 30px; + } +} + +/* User page */ + +.memberfontcreatedbtn { + border-radius: 7px; + border-color: #31bb6b; + background-color: #31bb6b; + color: 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: #31bb6b; + transition: 0.5s; +} + +.activeBtn:hover { + color: #fff; + background: #23864c; + transition: 0.5s; +} + +.inactiveBtn { + width: 100%; + display: flex; + color: #31bb6b; + border: 1px solid #31bb6a60; + background-color: #fff; + transition: 0.5s; +} + +.inactiveBtn:hover { + color: #fff; + background: #31bb6b; + transition: 0.5s; +} + +.sidebarsticky > 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: #31bb6b; +} + +.inactiveBtn .bgFill { + background-color: #31bb6b; +} + +.inactiveBtn:hover .bgFill { + background-color: #fff; +} + +.inactiveBtn i { + color: #fff; +} + +.inactiveBtn:hover i { + color: #31bb6b; +} + +.topRadius { + border-top-left-radius: 16px; + border-top-right-radius: 16px; +} + +.inputColor { + background: #f1f3f6; +} + +.width60 { + width: 60%; +} + +.maxWidth40 { + max-width: 40%; +} + +.allRound { + border-radius: 16px; +} + +.WidthFit { + width: fit-content; +} + +.datebox { + 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; +} + +.datebox > 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; +} + +.datebox > div > div { + margin-left: 0px !important; +} + +.datebox > div > fieldset { + border: none !important; + /* background-color: #f1f3f6; */ + border-radius: var(--bs-border-radius) !important; +} + +.datebox > div { + margin: 0.5rem !important; + background-color: #f1f3f6; +} + +input::file-selector-button { + background-color: black; + color: white; +} + +.noOutline { + outline: none; +} + +.Outline { + outline: 1px solid var(--bs-gray-400); +} diff --git a/src/screens/MemberDetail/MemberDetail.test.tsx b/src/screens/MemberDetail/MemberDetail.test.tsx new file mode 100644 index 0000000000..e094354552 --- /dev/null +++ b/src/screens/MemberDetail/MemberDetail.test.tsx @@ -0,0 +1,600 @@ +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 = { + key: '123', + 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 new file mode 100644 index 0000000000..be9b891b3c --- /dev/null +++ b/src/screens/MemberDetail/MemberDetail.tsx @@ -0,0 +1,561 @@ +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 { languages } from 'utils/languages'; +import { UPDATE_USER_MUTATION } from 'GraphQl/Mutations/mutations'; +import { toast } from 'react-toastify'; +import { errorHandler } from 'utils/errorHandler'; +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 { 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 { + educationGradeEnum, + maritalStatusEnum, + genderEnum, + employmentStatusEnum, +} from 'utils/formEnumFields'; +import DynamicDropDown from 'components/DynamicDropDown/DynamicDropDown'; + +type MemberDetailProps = { + id?: string; // This is the userId +}; + +const MemberDetail: React.FC = ({ id }): JSX.Element => { + const { t } = useTranslation('translation', { + keyPrefix: 'memberDetail', + }); + const { t: tCommon } = useTranslation('common'); + const location = useLocation(); + const isMounted = useRef(true); + const { getItem, setItem } = useLocalStorage(); + const currentUrl = location.state?.id || getItem('id') || id; + document.title = t('title'); + const [formState, setFormState] = useState({ + firstName: '', + lastName: '', + email: '', + appLanguageCode: '', + image: '', + gender: '', + birthDate: '2024-03-14', + grade: '', + empStatus: '', + maritalStatus: '', + phoneNumber: '', + address: '', + state: '', + city: '', + country: '', + pluginCreationAllowed: false, + }); + // Handle date change + const handleDateChange = (date: Dayjs | null): void => { + if (date) { + setFormState((prevState) => ({ + ...prevState, + birthDate: dayjs(date).format('YYYY-MM-DD'), // Convert Dayjs object to JavaScript Date object + })); + } + }; + 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 userData = user?.user; + + useEffect(() => { + if (userData && isMounted) { + // console.log(userData); + setFormState({ + ...formState, + firstName: userData?.user?.firstName, + lastName: userData?.user?.lastName, + email: userData?.user?.email, + appLanguageCode: userData?.appUserProfile?.appLanguageCode, + gender: userData?.user?.gender, + birthDate: userData?.user?.birthDate || '2020-03-14', + grade: userData?.user?.educationGrade, + empStatus: userData?.user?.employmentStatus, + maritalStatus: userData?.user?.maritalStatus, + phoneNumber: userData?.user?.phone?.mobile, + address: userData.user?.address?.line1, + state: userData?.user?.address?.state, + city: userData?.user?.address?.city, + country: userData?.user?.address?.countryCode, + pluginCreationAllowed: userData?.appUserProfile?.pluginCreationAllowed, + image: userData?.user?.image || '', + }); + } + }, [userData, user]); + + useEffect(() => { + // check component is mounted or not + return () => { + isMounted.current = false; + }; + }, []); + + 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 handlePhoneChange = (e: React.ChangeEvent): void => { + // const { name, value } = e.target; + // setFormState({ + // ...formState, + // phoneNumber: { + // ...formState.phoneNumber, + // [name]: value, + // }, + // }); + // // console.log(formState); + // }; + + 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 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) { + if (getItem('id') === currentUrl) { + setItem('FirstName', firstName); + setItem('LastName', lastName); + setItem('Email', email); + setItem('UserImage', image); + } + toast.success(tCommon('successfullyUpdated')); + } + } catch (error: unknown) { + if (error instanceof Error) { + errorHandler(t, error); + } + } + } catch (error: unknown) { + /* istanbul ignore next */ + if (error instanceof Error) { + errorHandler(t, error); + } + } + }; + + if (loading) { + return ; + } + + const sanitizedSrc = sanitizeHtml(formState.image, { + allowedTags: ['img'], + allowedAttributes: { + img: ['src', 'alt'], + }, + }); + + return ( + +
    +
    +
    + {/* Personal */} +
    +
    +

    {t('personalInfoHeading')}

    +
    +
    +
    +

    {tCommon('firstName')}

    + +
    +
    +

    {tCommon('lastName')}

    + +
    +
    +

    {t('gender')}

    +
    + +
    +
    +
    +

    {t('birthDate')}

    +
    + +
    +
    +
    +

    {t('educationGrade')}

    + +
    +
    +

    {t('employmentStatus')}

    + +
    +
    +

    {t('maritalStatus')}

    + +
    +

    + +

    +
    +
    + {/* Contact Info */} +
    +
    +

    {t('contactInfoHeading')}

    +
    +
    +
    +

    {t('phone')}

    + +
    +
    +

    {tCommon('email')}

    + +
    +
    +

    {tCommon('address')}

    + +
    +
    +

    {t('countryCode')}

    + +
    +
    +

    {t('city')}

    + +
    +
    +

    {t('state')}

    + +
    +
    +
    +
    +
    + {/* Personal */} +
    +
    +

    {t('personalDetailsHeading')}

    +
    +
    +
    + {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('actionsHeading')}

    +
    +
    +
    +
    + +

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

    +
    +
    +
    +
    +
    + +
    +
    +
    + + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + ); +}; +export const prettyDate = (param: string): string => { + const date = new Date(param); + if (date?.toDateString() === 'Invalid Date') { + return 'Unavailable'; + } + const day = date.getDate(); + const month = date.toLocaleString('default', { month: 'long' }); + const year = date.getFullYear(); + return `${day} ${month} ${year}`; +}; +export const getLanguageName = (code: string): string => { + let language = 'Unavailable'; + languages.map((data) => { + if (data.code == code) { + language = data.name; + } + }); + return language; +}; +export default MemberDetail; diff --git a/src/screens/OrgContribution/OrgContribution.module.css b/src/screens/OrgContribution/OrgContribution.module.css new file mode 100644 index 0000000000..7ca9333bf7 --- /dev/null +++ b/src/screens/OrgContribution/OrgContribution.module.css @@ -0,0 +1,261 @@ +.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.test.tsx new file mode 100644 index 0000000000..d2abc134df --- /dev/null +++ b/src/screens/OrgContribution/OrgContribution.test.tsx @@ -0,0 +1,47 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { act, render } 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 OrgContribution from './OrgContribution'; +import { store } from 'state/store'; +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); + }); + }); +} + +describe('Organisation Contribution Page', () => { + test('should render props and text elements test for the screen', async () => { + window.location.assign('/orglist'); + + const { container } = render( + + + + + + + + + , + ); + + 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'); + }); +}); diff --git a/src/screens/OrgContribution/OrgContribution.tsx b/src/screens/OrgContribution/OrgContribution.tsx new file mode 100644 index 0000000000..bcd8641609 --- /dev/null +++ b/src/screens/OrgContribution/OrgContribution.tsx @@ -0,0 +1,74 @@ +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'; + +function orgContribution(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'orgContribution', + }); + + document.title = t('title'); + + return ( + <> + + +
    +
    +
    {t('filterByName')}
    + + +
    {t('filterByTransId')}
    + + +
    {t('recentStats')}
    + +
    +
    + + +
    + +

    {t('contribution')}

    +
    + +
    + +
    + + ); +} + +export default orgContribution; diff --git a/src/screens/OrgList/OrgList.module.css b/src/screens/OrgList/OrgList.module.css new file mode 100644 index 0000000000..9da1ecbb70 --- /dev/null +++ b/src/screens/OrgList/OrgList.module.css @@ -0,0 +1,323 @@ +.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 new file mode 100644 index 0000000000..e7e0f7d4be --- /dev/null +++ b/src/screens/OrgList/OrgList.test.tsx @@ -0,0 +1,536 @@ +// SKIP_LOCALSTORAGE_CHECK +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { + act, + render, + screen, + fireEvent, + cleanup, + waitFor, +} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import 'jest-localstorage-mock'; +import 'jest-location-mock'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18nForTest from 'utils/i18nForTest'; +import OrgList from './OrgList'; + +import { + MOCKS, + MOCKS_ADMIN, + MOCKS_EMPTY, + MOCKS_WITH_ERROR, +} from './OrgListMocks'; +import { ToastContainer, toast } from 'react-toastify'; + +jest.setTimeout(30000); +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem } = useLocalStorage(); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +afterEach(() => { + localStorage.clear(); + cleanup(); +}); + +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); + + const formData = { + name: 'Dummy Organization', + description: 'This is a dummy organization', + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + image: new File(['hello'], 'hello.png', { type: 'image/png' }), + }; + test('Should display organisations for superAdmin even if admin For field is empty', async () => { + window.location.assign('/'); + setItem('id', '123'); + setItem('SuperAdmin', true); + setItem('AdminFor', []); + + render( + + + + + + + + + , + ); + + await wait(); + expect( + screen.queryByText('Organizations Not Found'), + ).not.toBeInTheDocument(); + }); + + test('Testing search functionality by pressing enter', async () => { + setItem('id', '123'); + setItem('SuperAdmin', true); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); + + render( + + + + + + + + + , + ); + await wait(); + + // Test that the search bar filters organizations by name + const searchBar = screen.getByTestId(/searchByName/i); + expect(searchBar).toBeInTheDocument(); + userEvent.type(searchBar, 'Dummy{enter}'); + }); + + test('Testing search functionality by Btn click', async () => { + setItem('id', '123'); + setItem('SuperAdmin', true); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); + render( + + + + + + + + + , + ); + await wait(); + + const searchBar = screen.getByTestId('searchByName'); + const searchBtn = screen.getByTestId('searchBtn'); + userEvent.type(searchBar, 'Dummy'); + fireEvent.click(searchBtn); + }); + + test('Should render no organisation warning alert when there are no organization', async () => { + window.location.assign('/'); + setItem('id', '123'); + setItem('SuperAdmin', true); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); + + render( + + + + + + + + + , + ); + + await wait(); + expect(screen.queryByText('Organizations Not Found')).toBeInTheDocument(); + expect( + screen.queryByText('Please create an organization through dashboard'), + ).toBeInTheDocument(); + expect(window.location).toBeAt('/'); + }); + + test('Testing Organization data is not present', async () => { + setItem('id', '123'); + setItem('SuperAdmin', false); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); + + render( + + + + + + + , + ); + + await wait(); + }); + + test('Testing create organization modal', async () => { + setItem('id', '123'); + setItem('SuperAdmin', true); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); + + render( + + + + + + + + + , + ); + + screen.debug(); + + expect(localStorage.setItem).toHaveBeenLastCalledWith( + 'Talawa-admin_AdminFor', + JSON.stringify([{ name: 'adi', _id: '1234', image: '' }]), + ); + + expect(screen.getByTestId(/createOrganizationBtn/i)).toBeInTheDocument(); + }); + + test('Create organization model should work properly', async () => { + setItem('id', '123'); + setItem('SuperAdmin', true); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); + + render( + + + + + + + + + + , + ); + + await wait(500); + + expect(localStorage.setItem).toHaveBeenLastCalledWith( + 'Talawa-admin_AdminFor', + JSON.stringify([{ name: 'adi', _id: '1234', image: '' }]), + ); + + userEvent.click(screen.getByTestId(/createOrganizationBtn/i)); + + userEvent.type(screen.getByTestId(/modalOrganizationName/i), formData.name); + userEvent.type( + screen.getByPlaceholderText(/Description/i), + formData.description, + ); + userEvent.type(screen.getByPlaceholderText(/City/i), formData.address.city); + userEvent.type( + screen.getByPlaceholderText(/Postal Code/i), + formData.address.postalCode, + ); + userEvent.type( + screen.getByPlaceholderText(/State \/ Province/i), + formData.address.state, + ); + + userEvent.selectOptions( + screen.getByTestId('countrycode'), + formData.address.countryCode, + ); + userEvent.type( + screen.getByPlaceholderText(/Line 1/i), + formData.address.line1, + ); + userEvent.type( + screen.getByPlaceholderText(/Line 2/i), + formData.address.line2, + ); + userEvent.type( + screen.getByPlaceholderText(/Sorting Code/i), + formData.address.sortingCode, + ); + userEvent.type( + screen.getByPlaceholderText(/Dependent Locality/i), + formData.address.dependentLocality, + ); + userEvent.click(screen.getByTestId(/userRegistrationRequired/i)); + userEvent.click(screen.getByTestId(/visibleInSearch/i)); + + expect(screen.getByTestId(/modalOrganizationName/i)).toHaveValue( + formData.name, + ); + expect(screen.getByPlaceholderText(/Description/i)).toHaveValue( + formData.description, + ); + //Checking the fields for the address object in the formdata. + const { address } = formData; + expect(screen.getByPlaceholderText(/City/i)).toHaveValue(address.city); + expect(screen.getByPlaceholderText(/State \/ Province/i)).toHaveValue( + address.state, + ); + expect(screen.getByPlaceholderText(/Dependent Locality/i)).toHaveValue( + address.dependentLocality, + ); + expect(screen.getByPlaceholderText(/Line 1/i)).toHaveValue(address.line1); + expect(screen.getByPlaceholderText(/Line 2/i)).toHaveValue(address.line2); + expect(screen.getByPlaceholderText(/Postal Code/i)).toHaveValue( + address.postalCode, + ); + expect(screen.getByTestId(/countrycode/i)).toHaveValue(address.countryCode); + expect(screen.getByPlaceholderText(/Sorting Code/i)).toHaveValue( + address.sortingCode, + ); + expect(screen.getByTestId(/userRegistrationRequired/i)).not.toBeChecked(); + expect(screen.getByTestId(/visibleInSearch/i)).toBeChecked(); + expect(screen.getByLabelText(/Display Image/i)).toBeTruthy(); + const displayImage = screen.getByTestId('organisationImage'); + userEvent.upload(displayImage, formData.image); + userEvent.click(screen.getByTestId(/submitOrganizationForm/i)); + await waitFor(() => { + expect( + screen.queryByText(/Congratulation the Organization is created/i), + ).toBeInTheDocument(); + }); + }); + + test('Plugin Notification model should work properly', async () => { + setItem('id', '123'); + setItem('SuperAdmin', true); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); + + render( + + + + + + + + + + , + ); + + await wait(500); + + expect(localStorage.setItem).toHaveBeenLastCalledWith( + 'Talawa-admin_AdminFor', + JSON.stringify([{ name: 'adi', _id: '1234', image: '' }]), + ); + + userEvent.click(screen.getByTestId(/createOrganizationBtn/i)); + + userEvent.type(screen.getByTestId(/modalOrganizationName/i), formData.name); + userEvent.type( + screen.getByPlaceholderText(/Description/i), + formData.description, + ); + userEvent.type(screen.getByPlaceholderText(/City/i), formData.address.city); + userEvent.type( + screen.getByPlaceholderText(/State \/ Province/i), + formData.address.state, + ); + userEvent.type( + screen.getByPlaceholderText(/Postal Code/i), + formData.address.postalCode, + ); + userEvent.selectOptions( + screen.getByTestId('countrycode'), + formData.address.countryCode, + ); + userEvent.type( + screen.getByPlaceholderText(/Line 1/i), + formData.address.line1, + ); + userEvent.type( + screen.getByPlaceholderText(/Line 2/i), + formData.address.line2, + ); + userEvent.type( + screen.getByPlaceholderText(/Sorting Code/i), + formData.address.sortingCode, + ); + userEvent.type( + screen.getByPlaceholderText(/Dependent Locality/i), + formData.address.dependentLocality, + ); + userEvent.click(screen.getByTestId(/userRegistrationRequired/i)); + userEvent.click(screen.getByTestId(/visibleInSearch/i)); + + expect(screen.getByTestId(/modalOrganizationName/i)).toHaveValue( + formData.name, + ); + expect(screen.getByPlaceholderText(/Description/i)).toHaveValue( + formData.description, + ); + //Checking the fields for the address object in the formdata. + const { address } = formData; + expect(screen.getByPlaceholderText(/City/i)).toHaveValue(address.city); + expect(screen.getByPlaceholderText(/State \/ Province/i)).toHaveValue( + address.state, + ); + expect(screen.getByPlaceholderText(/Dependent Locality/i)).toHaveValue( + address.dependentLocality, + ); + expect(screen.getByPlaceholderText(/Line 1/i)).toHaveValue(address.line1); + expect(screen.getByPlaceholderText(/Line 2/i)).toHaveValue(address.line2); + expect(screen.getByPlaceholderText(/Postal Code/i)).toHaveValue( + address.postalCode, + ); + expect(screen.getByTestId(/countrycode/i)).toHaveValue(address.countryCode); + expect(screen.getByPlaceholderText(/Sorting Code/i)).toHaveValue( + address.sortingCode, + ); + expect(screen.getByTestId(/userRegistrationRequired/i)).not.toBeChecked(); + expect(screen.getByTestId(/visibleInSearch/i)).toBeChecked(); + expect(screen.getByLabelText(/Display Image/i)).toBeTruthy(); + + userEvent.click(screen.getByTestId(/submitOrganizationForm/i)); + // await act(async () => { + // await new Promise((resolve) => setTimeout(resolve, 1000)); + // }); + await waitFor(() => + expect( + screen.queryByText(/Congratulation the Organization is created/i), + ).toBeInTheDocument(), + ); + await waitFor(() => { + screen.findByTestId(/pluginNotificationHeader/i); + }); + // userEvent.click(screen.getByTestId(/enableEverythingForm/i)); + userEvent.click(screen.getByTestId(/enableEverythingForm/i)); + }); + + test('Testing create sample organization working properly', async () => { + setItem('id', '123'); + setItem('SuperAdmin', true); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); + + render( + + + + + + + + + + , + ); + await wait(); + userEvent.click(screen.getByTestId(/createOrganizationBtn/i)); + userEvent.click(screen.getByTestId(/createSampleOrganizationBtn/i)); + await waitFor(() => + expect( + screen.queryByText(/Sample Organization Successfully created/i), + ).toBeInTheDocument(), + ); + }); + test('Testing error handling for CreateSampleOrg', async () => { + setItem('id', '123'); + setItem('SuperAdmin', true); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); + + jest.spyOn(toast, 'error'); + render( + + + + + + + + , + ); + await wait(); + userEvent.click(screen.getByTestId(/createOrganizationBtn/i)); + userEvent.click(screen.getByTestId(/createSampleOrganizationBtn/i)); + await waitFor(() => + expect( + screen.queryByText(/Only one sample organization allowed/i), + ).toBeInTheDocument(), + ); + }); +}); + +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); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); + + render( + + + + + + + + + , + ); + await waitFor(() => { + expect(screen.queryByText(/Create Organization/i)).toBeNull(); + }); + }); + test('Testing sort latest and oldest toggle', async () => { + setItem('id', '123'); + setItem('SuperAdmin', false); + setItem('AdminFor', [{ name: 'adi', _id: 'a0', image: '' }]); + + await act(async () => { + render( + + + + + + + + + , + ); + + await wait(); + + const searchInput = screen.getByTestId('sort'); + expect(searchInput).toBeInTheDocument(); + + const inputText = screen.getByTestId('sortOrgs'); + + fireEvent.click(inputText); + const toggleText = screen.getByTestId('latest'); + + fireEvent.click(toggleText); + + expect(searchInput).toBeInTheDocument(); + fireEvent.click(inputText); + const toggleTite = screen.getByTestId('oldest'); + fireEvent.click(toggleTite); + expect(searchInput).toBeInTheDocument(); + }); + }); +}); diff --git a/src/screens/OrgList/OrgList.tsx b/src/screens/OrgList/OrgList.tsx new file mode 100644 index 0000000000..5c91678217 --- /dev/null +++ b/src/screens/OrgList/OrgList.tsx @@ -0,0 +1,577 @@ +import { useMutation, useQuery } from '@apollo/client'; +import { Search } from '@mui/icons-material'; +import SortIcon from '@mui/icons-material/Sort'; +import { + CREATE_ORGANIZATION_MUTATION, + CREATE_SAMPLE_ORGANIZATION_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import { + ORGANIZATION_CONNECTION_LIST, + USER_ORGANIZATION_LIST, +} from 'GraphQl/Queries/Queries'; + +import OrgListCard from 'components/OrgListCard/OrgListCard'; +import type { ChangeEvent } from 'react'; +import React, { useEffect, useState } from 'react'; +import { Dropdown, Form } from 'react-bootstrap'; +import Button from 'react-bootstrap/Button'; +import Modal from 'react-bootstrap/Modal'; +import { useTranslation } from 'react-i18next'; +import InfiniteScroll from 'react-infinite-scroll-component'; +import { Link } from 'react-router-dom'; +import { toast } from 'react-toastify'; +import { errorHandler } from 'utils/errorHandler'; +import type { + InterfaceOrgConnectionInfoType, + InterfaceOrgConnectionType, + InterfaceUserType, +} from 'utils/interfaces'; +import useLocalStorage from 'utils/useLocalstorage'; +import styles from './OrgList.module.css'; +import OrganizationModal from './OrganizationModal'; + +function orgList(): JSX.Element { + const { t } = useTranslation('translation', { keyPrefix: 'orgList' }); + const { t: tCommon } = useTranslation('common'); + const [dialogModalisOpen, setdialogModalIsOpen] = useState(false); + const [dialogRedirectOrgId, setDialogRedirectOrgId] = useState(''); + + function openDialogModal(redirectOrgId: string): void { + setDialogRedirectOrgId(redirectOrgId); + // console.log(redirectOrgId, dialogRedirectOrgId); + setdialogModalIsOpen(true); + } + + const { getItem } = useLocalStorage(); + const superAdmin = getItem('SuperAdmin'); + const adminFor = getItem('AdminFor'); + + function closeDialogModal(): void { + setdialogModalIsOpen(false); + } + const toggleDialogModal = /* istanbul ignore next */ (): void => + setdialogModalIsOpen(!dialogModalisOpen); + document.title = t('title'); + + const perPageResult = 8; + const [isLoading, setIsLoading] = useState(true); + const [sortingState, setSortingState] = useState({ + option: '', + selectedOption: t('sort'), + }); + const [hasMore, sethasMore] = useState(true); + const [isLoadingMore, setIsLoadingMore] = useState(false); + const [searchByName, setSearchByName] = useState(''); + const [showModal, setShowModal] = useState(false); + const [formState, setFormState] = useState({ + name: '', + descrip: '', + userRegistrationRequired: true, + visible: false, + address: { + city: '', + countryCode: '', + dependentLocality: '', + line1: '', + line2: '', + postalCode: '', + sortingCode: '', + state: '', + }, + image: '', + }); + + const toggleModal = (): void => setShowModal(!showModal); + + const [create] = useMutation(CREATE_ORGANIZATION_MUTATION); + + const [createSampleOrganization] = useMutation( + CREATE_SAMPLE_ORGANIZATION_MUTATION, + ); + + const { + data: userData, + error: errorUser, + }: { + data: InterfaceUserType | undefined; + loading: boolean; + error?: Error | undefined; + } = useQuery(USER_ORGANIZATION_LIST, { + variables: { userId: getItem('id') }, + context: { + headers: { authorization: `Bearer ${getItem('token')}` }, + }, + }); + + const { + data: orgsData, + loading, + error: errorList, + refetch: refetchOrgs, + fetchMore, + } = useQuery(ORGANIZATION_CONNECTION_LIST, { + variables: { + first: perPageResult, + skip: 0, + filter: searchByName, + orderBy: + sortingState.option === 'Latest' ? 'createdAt_DESC' : 'createdAt_ASC', + }, + notifyOnNetworkStatusChange: true, + }); + + // To clear the search field and form fields on unmount + useEffect(() => { + return () => { + setSearchByName(''); + setFormState({ + name: '', + descrip: '', + userRegistrationRequired: true, + visible: false, + address: { + city: '', + countryCode: '', + dependentLocality: '', + line1: '', + line2: '', + postalCode: '', + sortingCode: '', + state: '', + }, + image: '', + }); + }; + }, []); + + useEffect(() => { + setIsLoading(loading && isLoadingMore); + }, [loading]); + + /* istanbul ignore next */ + const isAdminForCurrentOrg = ( + currentOrg: InterfaceOrgConnectionInfoType, + ): boolean => { + if (adminFor.length === 1) { + // If user is admin for one org only then check if that org is current org + return adminFor[0]._id === currentOrg._id; + } else { + // If user is admin for more than one org then check if current org is present in adminFor array + return ( + adminFor.some( + (org: { _id: string; name: string; image: string | null }) => + org._id === currentOrg._id, + ) ?? false + ); + } + }; + + const triggerCreateSampleOrg = (): void => { + createSampleOrganization() + .then(() => { + toast.success(t('sampleOrgSuccess')); + window.location.reload(); + }) + .catch(() => { + toast.error(t('sampleOrgDuplicate')); + }); + }; + + const createOrg = async (e: ChangeEvent): Promise => { + e.preventDefault(); + + const { + name: _name, + descrip: _descrip, + address: _address, + visible, + userRegistrationRequired, + image, + } = formState; + + const name = _name.trim(); + const descrip = _descrip.trim(); + const address = _address; + + try { + const { data } = await create({ + variables: { + name: name, + description: descrip, + address: address, + visibleInSearch: visible, + userRegistrationRequired: userRegistrationRequired, + image: image, + }, + }); + + /* istanbul ignore next */ + if (data) { + toast.success('Congratulation the Organization is created'); + refetchOrgs(); + openDialogModal(data.createOrganization._id); + setFormState({ + name: '', + descrip: '', + userRegistrationRequired: true, + visible: false, + address: { + city: '', + countryCode: '', + dependentLocality: '', + line1: '', + line2: '', + postalCode: '', + sortingCode: '', + state: '', + }, + image: '', + }); + toggleModal(); + } + } catch (error: unknown) { + /* istanbul ignore next */ + errorHandler(t, error); + } + }; + + /* istanbul ignore next */ + if (errorList || errorUser) { + window.location.assign('/'); + } + + /* istanbul ignore next */ + const resetAllParams = (): void => { + refetchOrgs({ + filter: '', + first: perPageResult, + skip: 0, + orderBy: + sortingState.option === 'Latest' ? 'createdAt_DESC' : 'createdAt_ASC', + }); + sethasMore(true); + }; + + /* istanbul ignore next */ + const handleSearch = (value: string): void => { + setSearchByName(value); + if (value === '') { + resetAllParams(); + return; + } + refetchOrgs({ + filter: value, + }); + }; + + const handleSearchByEnter = ( + e: React.KeyboardEvent, + ): void => { + if (e.key === 'Enter') { + const { value } = e.currentTarget; + handleSearch(value); + } + }; + + const handleSearchByBtnClick = (): void => { + const inputElement = document.getElementById( + 'searchOrgname', + ) as HTMLInputElement; + const inputValue = inputElement?.value || ''; + handleSearch(inputValue); + }; + /* istanbul ignore next */ + const loadMoreOrganizations = (): void => { + console.log('loadMoreOrganizations'); + setIsLoadingMore(true); + fetchMore({ + variables: { + skip: orgsData?.organizationsConnection.length || 0, + }, + updateQuery: ( + prev: + | { organizationsConnection: InterfaceOrgConnectionType[] } + | undefined, + { + fetchMoreResult, + }: { + fetchMoreResult: + | { organizationsConnection: InterfaceOrgConnectionType[] } + | undefined; + }, + ): + | { organizationsConnection: InterfaceOrgConnectionType[] } + | undefined => { + setIsLoadingMore(false); + if (!fetchMoreResult) return prev; + if (fetchMoreResult.organizationsConnection.length < perPageResult) { + sethasMore(false); + } + return { + organizationsConnection: [ + ...(prev?.organizationsConnection || []), + ...(fetchMoreResult.organizationsConnection || []), + ], + }; + }, + }); + }; + + const handleSorting = (option: string): void => { + setSortingState({ + option, + selectedOption: t(option), + }); + + const orderBy = option === 'Latest' ? 'createdAt_DESC' : 'createdAt_ASC'; + + refetchOrgs({ + first: perPageResult, + skip: 0, + filter: searchByName, + orderBy, + }); + }; + + return ( + <> + {/* Buttons Container */} +
    +
    + + +
    +
    +
    + +
    + {superAdmin && ( + + )} +
    +
    + {/* Text Infos for list */} + {!isLoading && + (!orgsData?.organizationsConnection || + orgsData.organizationsConnection.length === 0) && + searchByName.length === 0 && + (!userData || adminFor.length === 0 || superAdmin) ? ( +
    +

    {t('noOrgErrorTitle')}

    +
    {t('noOrgErrorDescription')}
    +
    + ) : !isLoading && + orgsData?.organizationsConnection.length == 0 && + /* istanbul ignore next */ + searchByName.length > 0 ? ( + /* istanbul ignore next */ +
    +

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

    +
    + ) : ( + <> + + {[...Array(perPageResult)].map((_, index) => ( +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + ))} + + } + hasMore={hasMore} + className={styles.listBox} + data-testid="organizations-list" + endMessage={ +
    +
    {tCommon('endOfResults')}
    +
    + } + > + {userData && superAdmin + ? orgsData?.organizationsConnection.map( + (item: InterfaceOrgConnectionInfoType) => { + return ( +
    + +
    + ); + }, + ) + : userData && + adminFor.length > 0 && + orgsData?.organizationsConnection.map( + (item: InterfaceOrgConnectionInfoType) => { + if (isAdminForCurrentOrg(item)) { + return ( +
    + +
    + ); + } + }, + )} + + {isLoading && ( + <> + {[...Array(perPageResult)].map((_, index) => ( +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + ))} + + )} + + )} + {/* Create Organization Modal */} + {/** + * Renders the `OrganizationModal` component. + * + * @param showModal - A boolean indicating whether the modal should be displayed. + * @param toggleModal - A function to toggle the visibility of the modal. + * @param formState - The state of the form in the organization modal. + * @param setFormState - A function to update the state of the form in the organization modal. + * @param createOrg - A function to handle the submission of the organization creation form. + * @param t - A translation function for localization. + * @param userData - Information about the current user. + * @param triggerCreateSampleOrg - A function to trigger the creation of a sample organization. + * @returns JSX element representing the `OrganizationModal`. + */} + + {/* Plugin Notification Modal after Org is Created */} + + + + {t('manageFeatures')} + + + +
    +
    +

    + {t('manageFeaturesInfo')} +

    + +
    + + {t('goToStore')} + + {/* */} + +
    +
    +
    +
    +
    + + ); +} +export default orgList; diff --git a/src/screens/OrgList/OrgListMocks.ts b/src/screens/OrgList/OrgListMocks.ts new file mode 100644 index 0000000000..380313ffd5 --- /dev/null +++ b/src/screens/OrgList/OrgListMocks.ts @@ -0,0 +1,258 @@ +import { + CREATE_ORGANIZATION_MUTATION, + CREATE_SAMPLE_ORGANIZATION_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import { + ORGANIZATION_CONNECTION_LIST, + USER_ORGANIZATION_LIST, +} from 'GraphQl/Queries/Queries'; +import 'jest-location-mock'; +import type { + InterfaceOrgConnectionInfoType, + InterfaceUserType, +} from 'utils/interfaces'; + +const superAdminUser: InterfaceUserType = { + user: { + firstName: 'John', + lastName: 'Doe', + email: 'john.doe@akatsuki.com', + image: null, + }, +}; + +const adminUser: InterfaceUserType = { + user: { + ...superAdminUser.user, + }, +}; + +const organizations: InterfaceOrgConnectionInfoType[] = [ + { + _id: '1', + creator: { _id: 'xyz', firstName: 'John', lastName: 'Doe' }, + image: '', + name: 'Palisadoes Foundation', + createdAt: '02/02/2022', + admins: [ + { + _id: '123', + }, + ], + members: [ + { + _id: '234', + }, + ], + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + }, +]; + +for (let x = 0; x < 1; x++) { + organizations.push({ + _id: 'a' + x, + image: '', + name: 'name', + creator: { + _id: '123', + firstName: 'firstName', + lastName: 'lastName', + }, + admins: [ + { + _id: x + '1', + }, + ], + members: [ + { + _id: x + '2', + }, + ], + createdAt: new Date().toISOString(), + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + }); +} + +// MOCKS FOR SUPERADMIN +const MOCKS = [ + { + request: { + query: ORGANIZATION_CONNECTION_LIST, + variables: { + first: 8, + skip: 0, + filter: '', + orderBy: 'createdAt_ASC', + }, + notifyOnNetworkStatusChange: true, + }, + result: { + data: { + organizationsConnection: organizations, + }, + }, + }, + { + request: { + query: USER_ORGANIZATION_LIST, + variables: { userId: '123' }, + }, + result: { + data: { user: superAdminUser }, + }, + }, + { + request: { + query: CREATE_SAMPLE_ORGANIZATION_MUTATION, + }, + result: { + data: { + createSampleOrganization: { + id: '1', + name: 'Sample Organization', + }, + }, + }, + }, + { + request: { + query: CREATE_ORGANIZATION_MUTATION, + variables: { + description: 'This is a dummy organization', + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + name: 'Dummy Organization', + visibleInSearch: true, + userRegistrationRequired: false, + image: '', + }, + }, + result: { + data: { + createOrganization: { + _id: '1', + }, + }, + }, + }, +]; +const MOCKS_EMPTY = [ + { + request: { + query: ORGANIZATION_CONNECTION_LIST, + variables: { + first: 8, + skip: 0, + filter: '', + orderBy: 'createdAt_ASC', + }, + notifyOnNetworkStatusChange: true, + }, + result: { + data: { + organizationsConnection: [], + }, + }, + }, + { + request: { + query: USER_ORGANIZATION_LIST, + variables: { userId: '123' }, + }, + result: { + data: { user: superAdminUser }, + }, + }, +]; +const MOCKS_WITH_ERROR = [ + { + request: { + query: ORGANIZATION_CONNECTION_LIST, + variables: { + first: 8, + skip: 0, + filter: '', + orderBy: 'createdAt_ASC', + }, + notifyOnNetworkStatusChange: true, + }, + result: { + data: { + organizationsConnection: organizations, + }, + }, + }, + { + request: { + query: USER_ORGANIZATION_LIST, + variables: { userId: '123' }, + }, + result: { + data: { user: superAdminUser }, + }, + }, + { + request: { + query: CREATE_SAMPLE_ORGANIZATION_MUTATION, + }, + error: new Error('Failed to create sample organization'), + }, +]; + +// MOCKS FOR ADMIN +const MOCKS_ADMIN = [ + { + request: { + query: ORGANIZATION_CONNECTION_LIST, + variables: { + first: 8, + skip: 0, + filter: '', + orderBy: 'createdAt_ASC', + }, + notifyOnNetworkStatusChange: true, + }, + result: { + data: { + organizationsConnection: organizations, + }, + }, + }, + { + request: { + query: USER_ORGANIZATION_LIST, + variables: { userId: '123' }, + }, + result: { + data: { user: adminUser }, + }, + }, +]; + +export { MOCKS, MOCKS_ADMIN, MOCKS_EMPTY, MOCKS_WITH_ERROR }; diff --git a/src/screens/OrgList/OrganizationModal.tsx b/src/screens/OrgList/OrganizationModal.tsx new file mode 100644 index 0000000000..8a44d2b851 --- /dev/null +++ b/src/screens/OrgList/OrganizationModal.tsx @@ -0,0 +1,322 @@ +import React from 'react'; +import { Modal, Form, Row, Col, Button } from 'react-bootstrap'; +import convertToBase64 from 'utils/convertToBase64'; +import type { ChangeEvent } from 'react'; +import styles from './OrgList.module.css'; +import type { InterfaceAddress } from 'utils/interfaces'; +import { countryOptions } from 'utils/formEnumFields'; +import useLocalStorage from 'utils/useLocalstorage'; + +/** + * Represents the state of the form in the organization modal. + */ +interface InterfaceFormStateType { + name: string; + descrip: string; + userRegistrationRequired: boolean; + visible: boolean; + address: InterfaceAddress; + image: string; +} + +/** + * Represents a user type. + */ +interface InterfaceUserType { + user: { + firstName: string; + lastName: string; + image: string | null; + email: string; + }; + + // Add more properties if needed +} + +/** + * Represents the properties of the OrganizationModal component. + */ +interface InterfaceOrganizationModalProps { + showModal: boolean; + toggleModal: () => void; + formState: InterfaceFormStateType; + setFormState: (state: React.SetStateAction) => void; + createOrg: (e: ChangeEvent) => Promise; + t: (key: string) => string; + tCommon: (key: string) => string; + userData: InterfaceUserType | undefined; + triggerCreateSampleOrg: () => void; +} + +/** + * Represents the organization modal component. + */ + +const OrganizationModal: React.FC = ({ + showModal, + toggleModal, + formState, + setFormState, + createOrg, + t, + tCommon, + triggerCreateSampleOrg, +}) => { + // function to update the state of the parameters inside address. + const { getItem } = useLocalStorage(); + const superAdmin = getItem('SuperAdmin'); + const adminFor = getItem('AdminFor'); + + const handleInputChange = (fieldName: string, value: string): void => { + setFormState((prevState) => ({ + ...prevState, + address: { + ...prevState.address, + [fieldName]: value, + }, + })); + }; + return ( + + + + {t('createOrganization')} + + +
    + + {tCommon('name')} + { + const inputText = e.target.value; + if (inputText.length < 50) { + setFormState({ + ...formState, + name: e.target.value, + }); + } + }} + /> + {tCommon('description')} + { + const descriptionText = e.target.value; + if (descriptionText.length < 200) { + setFormState({ + ...formState, + descrip: e.target.value, + }); + } + }} + /> + {tCommon('address')} + + + { + const countryCode = e.target.value; + handleInputChange('countryCode', countryCode); + }} + > + + {countryOptions.map((country) => ( + + ))} + + + + handleInputChange('city', e.target.value)} + /> + + + + + handleInputChange('state', e.target.value)} + /> + + + + handleInputChange('dependentLocality', e.target.value) + } + /> + + + + + handleInputChange('line1', e.target.value)} + /> + + + handleInputChange('line2', e.target.value)} + /> + + + + + + handleInputChange('postalCode', e.target.value) + } + /> + + + + handleInputChange('sortingCode', e.target.value) + } + /> + + + + + + {t('userRegistrationRequired')} + + + setFormState({ + ...formState, + userRegistrationRequired: + !formState.userRegistrationRequired, + }) + } + /> + + + + {t('visibleInSearch')} + + + setFormState({ + ...formState, + visible: !formState.visible, + }) + } + /> + + + {tCommon('displayImage')} + => { + const target = e.target as HTMLInputElement; + const file = target.files && target.files[0]; + /* istanbul ignore else */ + if (file) + setFormState({ + ...formState, + image: await convertToBase64(file), + }); + }} + data-testid="organisationImage" + /> + + + +
    +
    + {tCommon('OR')} +
    + {(adminFor.length > 0 || superAdmin) && ( +
    + +
    + )} + +
    +
    +
    + ); +}; + +export default OrganizationModal; diff --git a/src/screens/OrgPost/OrgPost.module.css b/src/screens/OrgPost/OrgPost.module.css new file mode 100644 index 0000000000..e674efbc7a --- /dev/null +++ b/src/screens/OrgPost/OrgPost.module.css @@ -0,0 +1,325 @@ +.mainpage { + display: flex; + flex-direction: row; +} +.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; +} + +.btnsContainer input { + outline: 1px solid var(--bs-gray-400); +} + +.btnsContainer .input button { + width: 52px; +} + +.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; +} +.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; + align-items: center; + margin-bottom: 3rem; +} + +@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%; + } +} +@media screen and (max-width: 575.5px) { + .justifysp { + display: flex; + justify-content: space-between; + width: 100%; + } + + .mainpageright { + width: 98%; + } +} +.addbtn { + border: 1px solid #e8e5e5; + box-shadow: 0 2px 2px #e8e5e5; + border-radius: 5px; + font-size: 16px; + height: 60%; + width: 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: 20px 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%; +} +.postinfo { + height: 80px; +} + +.postinfo { + height: 80px; + margin-bottom: 20px; +} +.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; +} + +.closeButton { + 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; +} +.sidebarsticky > input { + text-decoration: none; + margin-bottom: 50px; + border: solid 1.5px #d3d3d3; + border-radius: 5px; + width: 80%; + border-radius: 7px; + padding-top: 5px; + padding-bottom: 5px; + padding-right: 10px; + padding-left: 10px; + text-decoration: none; + box-shadow: none; +} + +.sidebarsticky > input:focus { + border-color: #fff; + box-shadow: 0 0 5pt 0.5pt #d3d3d3; + outline: none; +} +button[data-testid='createPostBtn'] { + display: block; +} +.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); + } +} +.list_box { + height: 70vh; + overflow-y: auto; + width: auto; +} +@media only screen and (max-width: 600px) { + .form_wrapper { + width: 90%; + top: 45%; + } +} diff --git a/src/screens/OrgPost/OrgPost.test.tsx b/src/screens/OrgPost/OrgPost.test.tsx new file mode 100644 index 0000000000..465da98642 --- /dev/null +++ b/src/screens/OrgPost/OrgPost.test.tsx @@ -0,0 +1,662 @@ +import { MockedProvider } from '@apollo/react-testing'; +import { act, fireEvent, render, screen } 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 { BrowserRouter } from 'react-router-dom'; +import React from 'react'; +import { CREATE_POST_MUTATION } from 'GraphQl/Mutations/mutations'; +import { ORGANIZATION_POST_LIST } from 'GraphQl/Queries/Queries'; +import { ToastContainer } from 'react-toastify'; +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18nForTest from 'utils/i18nForTest'; +import OrgPost from './OrgPost'; +const MOCKS = [ + { + request: { + query: ORGANIZATION_POST_LIST, + variables: { + id: undefined, + after: null, + before: null, + first: 6, + last: null, + }, + }, + result: { + data: { + organizations: [ + { + posts: { + edges: [ + { + node: { + _id: '6411e53835d7ba2344a78e21', + title: 'postone', + text: 'This is the first post', + imageUrl: null, + videoUrl: null, + createdAt: '2023-08-24T09:26:56.524+00:00', + creator: { + _id: '640d98d9eb6a743d75341067', + firstName: 'Aditya', + lastName: 'Shelke', + email: 'adidacreator1@gmail.com', + }, + likeCount: 0, + commentCount: 0, + comments: [], + pinned: true, + likedBy: [], + }, + cursor: '6411e53835d7ba2344a78e21', + }, + { + node: { + _id: '6411e54835d7ba2344a78e29', + title: 'posttwo', + text: 'Tis is the post two', + imageUrl: null, + videoUrl: null, + createdAt: '2023-08-24T09:26:56.524+00:00', + creator: { + _id: '640d98d9eb6a743d75341067', + firstName: 'Aditya', + lastName: 'Shelke', + email: 'adidacreator1@gmail.com', + }, + likeCount: 0, + commentCount: 0, + pinned: false, + likedBy: [], + comments: [], + }, + cursor: '6411e54835d7ba2344a78e29', + }, + { + node: { + _id: '6411e54835d7ba2344a78e30', + title: 'posttwo', + text: 'Tis is the post two', + imageUrl: null, + videoUrl: null, + createdAt: '2023-08-24T09:26:56.524+00:00', + creator: { + _id: '640d98d9eb6a743d75341067', + firstName: 'Aditya', + lastName: 'Shelke', + email: 'adidacreator1@gmail.com', + }, + likeCount: 0, + commentCount: 0, + pinned: true, + likedBy: [], + comments: [], + }, + cursor: '6411e54835d7ba2344a78e30', + }, + { + node: { + _id: '6411e54835d7ba2344a78e31', + title: 'posttwo', + text: 'Tis is the post two', + imageUrl: null, + videoUrl: null, + createdAt: '2023-08-24T09:26:56.524+00:00', + creator: { + _id: '640d98d9eb6a743d75341067', + firstName: 'Aditya', + lastName: 'Shelke', + email: 'adidacreator1@gmail.com', + }, + likeCount: 0, + commentCount: 0, + pinned: false, + likedBy: [], + comments: [], + }, + cursor: '6411e54835d7ba2344a78e31', + }, + ], + pageInfo: { + startCursor: '6411e53835d7ba2344a78e21', + endCursor: '6411e54835d7ba2344a78e31', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 4, + }, + }, + ], + }, + }, + }, + { + request: { + query: CREATE_POST_MUTATION, + variables: { + title: 'Dummy Post', + text: 'This is dummy text', + organizationId: '123', + }, + result: { + data: { + createPost: { + _id: '453', + }, + }, + }, + }, + }, + { + request: { + query: CREATE_POST_MUTATION, + variables: { + title: 'Dummy Post', + text: 'This is dummy text', + organizationId: '123', + }, + result: { + data: { + createPost: { + _id: '453', + }, + }, + }, + }, + }, +]; +const link = new StaticMockLink(MOCKS, true); + +async function wait(ms = 500): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +describe('Organisation Post Page', () => { + const formData = { + posttitle: 'dummy post', + postinfo: 'This is a dummy post', + postImage: new File(['hello'], 'hello.png', { type: 'image/png' }), + postVideo: new File(['hello'], 'hello.mp4', { type: 'video/mp4' }), + }; + + test('correct mock data should be queried', async () => { + const dataQuery1 = MOCKS[0]?.result?.data?.organizations[0].posts.edges[0]; + + expect(dataQuery1).toEqual({ + node: { + _id: '6411e53835d7ba2344a78e21', + title: 'postone', + text: 'This is the first post', + imageUrl: null, + videoUrl: null, + createdAt: '2023-08-24T09:26:56.524+00:00', + creator: { + _id: '640d98d9eb6a743d75341067', + firstName: 'Aditya', + lastName: 'Shelke', + email: 'adidacreator1@gmail.com', + }, + likeCount: 0, + commentCount: 0, + pinned: true, + likedBy: [], + comments: [], + }, + cursor: '6411e53835d7ba2344a78e21', + }); + }); + + test('Testing create post functionality', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('createPostModalBtn')); + + userEvent.type(screen.getByTestId('modalTitle'), formData.posttitle); + + userEvent.type(screen.getByTestId('modalinfo'), formData.postinfo); + userEvent.upload(screen.getByTestId('addMediaField'), formData.postImage); + userEvent.upload(screen.getByTestId('addMediaField'), formData.postVideo); + userEvent.upload(screen.getByTestId('addMediaField'), formData.postImage); + userEvent.upload(screen.getByTestId('addMediaField'), formData.postVideo); + userEvent.click(screen.getByTestId('pinPost')); + expect(screen.getByTestId('pinPost')).toBeChecked(); + + userEvent.click(screen.getByTestId('createPostBtn')); + + await wait(); + + userEvent.click(screen.getByTestId('closeOrganizationModal')); + }, 15000); + + test('Testing search functionality', async () => { + render( + + + + + + + + + , + ); + async function debounceWait(ms = 200): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); + } + await debounceWait(); + userEvent.type(screen.getByPlaceholderText(/Search By/i), 'postone{enter}'); + await debounceWait(); + const sortDropdown = screen.getByTestId('sort'); + userEvent.click(sortDropdown); + }); + test('Testing search text and title toggle', async () => { + await act(async () => { + // Wrap the test code in act + render( + + + + + + + + + , + ); + + await wait(); + + const searchInput = screen.getByTestId('searchByName'); + expect(searchInput).toHaveAttribute('placeholder', 'Search By Title'); + + const inputText = screen.getByTestId('searchBy'); + + fireEvent.click(inputText); + const toggleText = screen.getByTestId('Text'); + + fireEvent.click(toggleText); + + expect(searchInput).toHaveAttribute('placeholder', 'Search By Text'); + fireEvent.click(inputText); + const toggleTite = screen.getByTestId('searchTitle'); + fireEvent.click(toggleTite); + expect(searchInput).toHaveAttribute('placeholder', 'Search By Title'); + }); + }); + test('Testing search latest and oldest toggle', async () => { + await act(async () => { + // Wrap the test code in act + render( + + + + + + + + + , + ); + + await wait(); + + const searchInput = screen.getByTestId('sort'); + expect(searchInput).toBeInTheDocument(); + + const inputText = screen.getByTestId('sortpost'); + + fireEvent.click(inputText); + const toggleText = screen.getByTestId('latest'); + + fireEvent.click(toggleText); + + expect(searchInput).toBeInTheDocument(); + fireEvent.click(inputText); + const toggleTite = screen.getByTestId('oldest'); + fireEvent.click(toggleTite); + expect(searchInput).toBeInTheDocument(); + }); + }); + test('After creating a post, the data should be refetched', async () => { + const refetchMock = jest.fn(); + + render( + + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('createPostModalBtn')); + + // Fill in post form fields... + + userEvent.click(screen.getByTestId('createPostBtn')); + + await wait(); + + expect(refetchMock).toHaveBeenCalledTimes(0); + }); + + test('Create post without media', async () => { + render( + + + + + + + + + + , + ); + + await wait(); + userEvent.click(screen.getByTestId('createPostModalBtn')); + + const postTitleInput = screen.getByTestId('modalTitle'); + fireEvent.change(postTitleInput, { target: { value: 'Test Post' } }); + + const postInfoTextarea = screen.getByTestId('modalinfo'); + fireEvent.change(postInfoTextarea, { + target: { value: 'Test post information' }, + }); + + const createPostBtn = screen.getByTestId('createPostBtn'); + fireEvent.click(createPostBtn); + }, 15000); + + test('Create post and preview', async () => { + render( + + + + + + + + + + , + ); + + await wait(); + userEvent.click(screen.getByTestId('createPostModalBtn')); + + const postTitleInput = screen.getByTestId('modalTitle'); + fireEvent.change(postTitleInput, { target: { value: 'Test Post' } }); + + const postInfoTextarea = screen.getByTestId('modalinfo'); + fireEvent.change(postInfoTextarea, { + target: { value: 'Test post information' }, + }); + + // Simulate uploading an image + const imageFile = new File(['image content'], 'image.png', { + type: 'image/png', + }); + const imageInput = screen.getByTestId('addMediaField'); + userEvent.upload(imageInput, imageFile); + + // Check if the image is displayed + const imagePreview = await screen.findByAltText('Post Image Preview'); + expect(imagePreview).toBeInTheDocument(); + + // Check if the close button for the image works + const closeButton = screen.getByTestId('mediaCloseButton'); + fireEvent.click(closeButton); + + // Check if the image is removed from the preview + expect(imagePreview).not.toBeInTheDocument(); + }, 15000); + + test('Modal opens and closes', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + const createPostModalBtn = screen.getByTestId('createPostModalBtn'); + + userEvent.click(createPostModalBtn); + + const modalTitle = screen.getByTestId('modalOrganizationHeader'); + expect(modalTitle).toBeInTheDocument(); + + const closeButton = screen.getByTestId(/modalOrganizationHeader/i); + userEvent.click(closeButton); + + await wait(); + + const closedModalTitle = screen.queryByText(/postDetail/i); + expect(closedModalTitle).not.toBeInTheDocument(); + }); + it('renders the form with input fields and buttons', async () => { + render( + + + + + + + + + + , + ); + + await wait(); + userEvent.click(screen.getByTestId('createPostModalBtn')); + + // Check if input fields and buttons are present + expect(screen.getByTestId('modalTitle')).toBeInTheDocument(); + expect(screen.getByTestId('modalinfo')).toBeInTheDocument(); + expect(screen.getByTestId('createPostBtn')).toBeInTheDocument(); + }); + + it('allows users to input data into the form fields', async () => { + render( + + + + + + + + + + , + ); + + await wait(); + userEvent.click(screen.getByTestId('createPostModalBtn')); + + // Simulate user input + fireEvent.change(screen.getByTestId('modalTitle'), { + target: { value: 'Test Title' }, + }); + fireEvent.change(screen.getByTestId('modalinfo'), { + target: { value: 'Test Info' }, + }); + + // Check if input values are set correctly + expect(screen.getByTestId('modalTitle')).toHaveValue('Test Title'); + expect(screen.getByTestId('modalinfo')).toHaveValue('Test Info'); + }); + + test('allows users to upload an image', async () => { + render( + + + + + + + + + + , + ); + + await wait(); + userEvent.click(screen.getByTestId('createPostModalBtn')); + + const postTitleInput = screen.getByTestId('modalTitle'); + fireEvent.change(postTitleInput, { target: { value: 'Test Post' } }); + + const postInfoTextarea = screen.getByTestId('modalinfo'); + fireEvent.change(postInfoTextarea, { + target: { value: 'Test post information' }, + }); + const file = new File(['image content'], 'image.png', { + type: 'image/png', + }); + const input = screen.getByTestId('addMediaField'); + userEvent.upload(input, file); + + await screen.findByAltText('Post Image Preview'); + expect(screen.getByAltText('Post Image Preview')).toBeInTheDocument(); + + const closeButton = screen.getByTestId('mediaCloseButton'); + fireEvent.click(closeButton); + }, 15000); + test('Create post, preview image, and close preview', async () => { + await act(async () => { + render( + + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('createPostModalBtn')); + + const postTitleInput = screen.getByTestId('modalTitle'); + fireEvent.change(postTitleInput, { target: { value: 'Test Post' } }); + + const postInfoTextarea = screen.getByTestId('modalinfo'); + fireEvent.change(postInfoTextarea, { + target: { value: 'Test post information' }, + }); + + const videoFile = new File(['video content'], 'video.mp4', { + type: 'video/mp4', + }); + + userEvent.upload(screen.getByTestId('addMediaField'), videoFile); + + // Check if the video is displayed + const videoPreview = await screen.findByTestId('videoPreview'); + expect(videoPreview).toBeInTheDocument(); + + // Check if the close button for the video works + const closeVideoPreviewButton = screen.getByTestId('mediaCloseButton'); + fireEvent.click(closeVideoPreviewButton); + expect(videoPreview).not.toBeInTheDocument(); + }); + }); + test('Sorting posts by pinned status', async () => { + // Mocked data representing posts with different pinned statuses + const mockedPosts = [ + { + _id: '1', + title: 'Post 1', + pinned: true, + }, + { + _id: '2', + title: 'Post 2', + pinned: false, + }, + { + _id: '3', + title: 'Post 3', + pinned: true, + }, + { + _id: '4', + title: 'Post 4', + pinned: true, + }, + ]; + + // Render the OrgPost component and pass the mocked data to it + render( + + + + + + + + + + , + ); + + await wait(); + + const sortedPosts = screen.getAllByTestId('post-item'); + + // Assert that the posts are sorted correctly + expect(sortedPosts).toHaveLength(mockedPosts.length); + expect(sortedPosts[0]).toHaveTextContent( + 'postoneThis is the first po... Aditya Shelke', + ); + expect(sortedPosts[1]).toHaveTextContent( + 'posttwoTis is the post two Aditya Shelke', + ); + expect(sortedPosts[2]).toHaveTextContent( + 'posttwoTis is the post two Aditya Shelke', + ); + }); +}); diff --git a/src/screens/OrgPost/OrgPost.tsx b/src/screens/OrgPost/OrgPost.tsx new file mode 100644 index 0000000000..29b7de0614 --- /dev/null +++ b/src/screens/OrgPost/OrgPost.tsx @@ -0,0 +1,559 @@ +import { useMutation, useQuery, type ApolloError } from '@apollo/client'; +import { Search } from '@mui/icons-material'; +import SortIcon from '@mui/icons-material/Sort'; +import { CREATE_POST_MUTATION } from 'GraphQl/Mutations/mutations'; +import { ORGANIZATION_POST_LIST } from 'GraphQl/Queries/Queries'; +import Loader from 'components/Loader/Loader'; +import NotFound from 'components/NotFound/NotFound'; +import OrgPostCard from 'components/OrgPostCard/OrgPostCard'; +import { useNavigate, useParams } from 'react-router-dom'; +import type { ChangeEvent } 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'; +import Modal from 'react-bootstrap/Modal'; +import Row from 'react-bootstrap/Row'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; +import convertToBase64 from 'utils/convertToBase64'; +import { errorHandler } from 'utils/errorHandler'; +import type { InterfaceQueryOrganizationPostListItem } from 'utils/interfaces'; +import styles from './OrgPost.module.css'; + +interface InterfaceOrgPost { + _id: string; + title: string; + text: string; + imageUrl: string | null; + videoUrl: string | null; + creator: { _id: string; firstName: string; lastName: string; email: string }; + pinned: boolean; + createdAt: string; + likeCount: number; + commentCount: number; + likedBy: { _id: string }[]; + comments: { + _id: string; + text: string; + creator: { _id: string }; + createdAt: string; + likeCount: number; + likedBy: { _id: string }[]; + }[]; +} + +function orgPost(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'orgPost', + }); + const { t: tCommon } = useTranslation('common'); + + document.title = t('title'); + const [postmodalisOpen, setPostModalIsOpen] = useState(false); + const [postformState, setPostFormState] = useState({ + posttitle: '', + postinfo: '', + postImage: '', + postVideo: '', + addMedia: '', + pinPost: false, + }); + const [sortingOption, setSortingOption] = useState('latest'); + const [file, setFile] = useState(null); + const { orgId: currentUrl } = useParams(); + const navigate = useNavigate(); + const [showTitle, setShowTitle] = useState(true); + const [after, setAfter] = useState(null); + const [before, setBefore] = useState(null); + const [first, setFirst] = useState(6); + const [last, setLast] = useState(null); + + const showInviteModal = (): void => { + setPostModalIsOpen(true); + }; + + const hideInviteModal = (): void => { + setPostModalIsOpen(false); + setPostFormState({ + posttitle: '', + postinfo: '', + postImage: '', + postVideo: '', + addMedia: '', + pinPost: false, + }); + }; + + const { + data: orgPostListData, + loading: orgPostListLoading, + error: orgPostListError, + refetch, + }: { + data?: { + organizations: InterfaceQueryOrganizationPostListItem[]; + }; + loading: boolean; + error?: ApolloError; + refetch: (filterData?: { + id: string | undefined; + title_contains: string | null; + text_contains: string | null; + }) => void; + } = useQuery(ORGANIZATION_POST_LIST, { + variables: { + id: currentUrl, + after: after, + before: before, + first: first, + last: last, + }, + }); + const [create, { loading: createPostLoading }] = + useMutation(CREATE_POST_MUTATION); + const [displayedPosts, setDisplayedPosts] = useState( + orgPostListData?.organizations[0].posts.edges.map((edge) => edge.node) || + [], + ); + + // ... + + useEffect(() => { + if (orgPostListData && orgPostListData.organizations) { + const newDisplayedPosts: InterfaceOrgPost[] = sortPosts( + orgPostListData.organizations[0].posts.edges.map((edge) => edge.node), + sortingOption, + ); + setDisplayedPosts(newDisplayedPosts); + } + }, [orgPostListData, sortingOption]); + + const createPost = async (e: ChangeEvent): Promise => { + e.preventDefault(); + + const { + posttitle: _posttitle, + postinfo: _postinfo, + postImage, + postVideo, + pinPost, + } = postformState; + + const posttitle = _posttitle.trim(); + const postinfo = _postinfo.trim(); + + try { + if (!posttitle || !postinfo) { + throw new Error('Text fields cannot be empty strings'); + } + + const { data } = await create({ + variables: { + title: posttitle, + text: postinfo, + organizationId: currentUrl, + file: postImage || postVideo || postformState.addMedia, + pinned: pinPost, + }, + }); + + /* istanbul ignore next */ + if (data) { + toast.success(t('postCreatedSuccess')); + refetch(); + setPostFormState({ + posttitle: '', + postinfo: '', + postImage: '', + postVideo: '', + addMedia: '', + pinPost: false, + }); + setPostModalIsOpen(false); + } + } catch (error: unknown) { + errorHandler(t, error); + } + }; + + useEffect(() => { + if (orgPostListError) { + navigate('/orglist'); + } + }, [orgPostListError]); + + if (createPostLoading || orgPostListLoading) { + return ; + } + + const handleAddMediaChange = async ( + e: React.ChangeEvent, + ): Promise => { + setPostFormState((prevPostFormState) => ({ + ...prevPostFormState, + addMedia: '', + })); + + const selectedFile = e.target.files?.[0]; + + if (selectedFile) { + setFile(selectedFile); + setPostFormState({ + ...postformState, + addMedia: await convertToBase64(selectedFile), + }); + } + }; + + const handleSearch = (e: React.ChangeEvent): void => { + const { value } = e.target; + const filterData = { + id: currentUrl, + title_contains: showTitle ? value : null, + text_contains: !showTitle ? value : null, + }; + refetch(filterData); + }; + + const debouncedHandleSearch = handleSearch; + + const handleSorting = (option: string): void => { + setSortingOption(option); + }; + const handleNextPage = (): void => { + setAfter(orgPostListData?.organizations[0].posts.pageInfo.endCursor); + setBefore(null); + setFirst(6); + setLast(null); + }; + const handlePreviousPage = (): void => { + setBefore(orgPostListData?.organizations[0].posts.pageInfo.startCursor); + setAfter(null); + setFirst(null); + setLast(6); + }; + // console.log(orgPostListData?.organizations[0].posts); + const sortPosts = ( + posts: InterfaceOrgPost[], + sortingOption: string, + ): InterfaceOrgPost[] => { + const sortedPosts = [...posts]; + + if (sortingOption === 'latest') { + sortedPosts.sort( + (a, b) => + new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), + ); + } else if (sortingOption === 'oldest') { + sortedPosts.sort( + (a, b) => + new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(), + ); + } + + return sortedPosts; + }; + + const sortedPostsList: InterfaceOrgPost[] = [...displayedPosts]; + sortedPostsList.sort((a: InterfaceOrgPost, b: InterfaceOrgPost) => { + if (a.pinned === b.pinned) { + return 0; + } + /* istanbul ignore next */ + if (a.pinned) { + return -1; + } + return 1; + }); + + return ( + <> + +
    +
    +
    + + +
    +
    +
    + + +
    + + +
    +
    +
    + {sortedPostsList && sortedPostsList.length > 0 ? ( + sortedPostsList.map( + (datas: { + _id: string; + title: string; + text: string; + imageUrl: string | null; + videoUrl: string | null; + + creator: { firstName: string; lastName: string }; + pinned: boolean; + }) => ( + + ), + ) + ) : ( + + )} +
    +
    +
    +
    + +
    +
    + +
    +
    +
    + + + {t('postDetails')} + +
    + + {t('postTitle')} + { + setPostFormState({ + ...postformState, + posttitle: e.target.value, + }); + }} + /> + {t('information')} + { + setPostFormState({ + ...postformState, + postinfo: e.target.value, + }); + }} + /> + + + {t('addMedia')} + + + {postformState.addMedia && file && ( +
    + {/* Display preview for both image and video */} + {file.type.startsWith('image') ? ( + Post Image Preview + ) : ( + + )} + +
    + )} + + {t('pinPost')} + + + setPostFormState({ + ...postformState, + pinPost: !postformState.pinPost, + }) + } + /> +
    + + + + + +
    +
    + + ); +} + +export default orgPost; diff --git a/src/screens/OrgSettings/OrgSettings.module.css b/src/screens/OrgSettings/OrgSettings.module.css new file mode 100644 index 0000000000..6910ff49ad --- /dev/null +++ b/src/screens/OrgSettings/OrgSettings.module.css @@ -0,0 +1,52 @@ +.settingsContainer { + min-height: 100vh; +} + +.settingsBody { + min-height: 100vh; + margin: 2.5rem 1rem; +} + +.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.2rem; + font-weight: 600; +} + +.cardBody { + min-height: 180px; +} + +.cardBody .textBox { + margin: 0 0 3rem 0; + color: var(--bs-secondary); +} + +hr { + border: none; + height: 1px; + background-color: var(--bs-gray-500); +} + +.settingsTabs { + display: none; +} + +@media (min-width: 577px) { + .settingsDropdown { + display: none; + } +} + +@media (min-width: 577px) { + .settingsTabs { + display: block; + } +} diff --git a/src/screens/OrgSettings/OrgSettings.test.tsx b/src/screens/OrgSettings/OrgSettings.test.tsx new file mode 100644 index 0000000000..d22c63dca6 --- /dev/null +++ b/src/screens/OrgSettings/OrgSettings.test.tsx @@ -0,0 +1,171 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { act, render, screen, waitFor } from '@testing-library/react'; +import 'jest-location-mock'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; + +import { DELETE_ORGANIZATION_MUTATION } from 'GraphQl/Mutations/mutations'; +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18nForTest from 'utils/i18nForTest'; +import OrgSettings from './OrgSettings'; +import { ORGANIZATIONS_LIST } from 'GraphQl/Queries/Queries'; +import userEvent from '@testing-library/user-event'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem } = useLocalStorage(); + +const MOCKS = [ + { + request: { + query: ORGANIZATIONS_LIST, + }, + result: { + data: { + organizations: [ + { + _id: '123', + image: null, + name: 'Palisadoes', + description: 'Equitable Access to STEM Education Jobs', + location: 'Jamaica', + isPublic: true, + visibleInSearch: false, + creator: { + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@example.com', + }, + members: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@gmail.com', + }, + admins: [ + { + _id: '123', + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@gmail.com', + }, + ], + membershipRequests: { + _id: '456', + user: { + firstName: 'Sam', + lastName: 'Smith', + email: 'samsmith@gmail.com', + }, + }, + blockedUsers: [], + }, + ], + }, + }, + }, + { + request: { + query: DELETE_ORGANIZATION_MUTATION, + }, + result: { + data: { + removeOrganization: [ + { + _id: 123, + }, + ], + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const translations = JSON.parse( + JSON.stringify(i18nForTest.getDataByLanguage('en')?.translation.orgSettings), +); + +afterEach(() => { + localStorage.clear(); +}); + +describe('Organisation Settings Page', () => { + test('correct mock data should be queried', async () => { + const dataQuery1 = MOCKS[1]?.result?.data?.removeOrganization; + expect(dataQuery1).toEqual([ + { + _id: 123, + }, + ]); + }); + + test('should render props and text elements test for the screen', async () => { + window.location.assign('/orgsetting/123'); + setItem('SuperAdmin', true); + render( + + + + + + + + + , + ); + + await wait(); + + expect(screen.getAllByText(/Delete Organization/i)).toHaveLength(3); + expect( + screen.getByText( + /By clicking on Delete Organization button the organization will be permanently deleted along with its events, tags and all related data/i, + ), + ).toBeInTheDocument(); + expect(screen.getByText(/Other Settings/i)).toBeInTheDocument(); + expect(screen.getByText(/Change Language/i)).toBeInTheDocument(); + expect(window.location).toBeAt('/orgsetting/123'); + }); + + test('should render appropriate settings based on the orgSetting state', async () => { + window.location.assign('/orgsetting/123'); + setItem('SuperAdmin', true); + + const { queryByText } = render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + userEvent.click(screen.getByTestId('actionItemCategoriesSettings')); + expect( + queryByText(translations.actionItemCategories), + ).toBeInTheDocument(); + }); + + await waitFor(() => { + userEvent.click(screen.getByTestId('generalSettings')); + expect(queryByText(translations.updateOrganization)).toBeInTheDocument(); + }); + }); +}); diff --git a/src/screens/OrgSettings/OrgSettings.tsx b/src/screens/OrgSettings/OrgSettings.tsx new file mode 100644 index 0000000000..8065911508 --- /dev/null +++ b/src/screens/OrgSettings/OrgSettings.tsx @@ -0,0 +1,147 @@ +import React, { useState } from 'react'; +import ChangeLanguageDropDown from 'components/ChangeLanguageDropdown/ChangeLanguageDropDown'; +import DeleteOrg from 'components/DeleteOrg/DeleteOrg'; +import OrgUpdate from 'components/OrgUpdate/OrgUpdate'; +import { Button, Card, Dropdown, Form } from 'react-bootstrap'; +import Col from 'react-bootstrap/Col'; +import Row from 'react-bootstrap/Row'; +import { useTranslation } from 'react-i18next'; +import styles from './OrgSettings.module.css'; +import OrgProfileFieldSettings from 'components/OrgProfileFieldSettings/OrgProfileFieldSettings'; +import OrgActionItemCategories from 'components/OrgActionItemCategories/OrgActionItemCategories'; +import { useParams } from 'react-router-dom'; + +type SettingType = 'general' | 'actionItemCategories'; + +function orgSettings(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'orgSettings', + }); + + const orgSettings: SettingType[] = ['general', 'actionItemCategories']; + + const [orgSetting, setOrgSetting] = useState('general'); + + document.title = t('title'); + const { orgId } = useParams(); + + return ( + <> +
    + + +
    + {orgSettings.map((setting, index) => ( + + ))} +
    + + + + {t(orgSetting)} + + + {orgSettings.map((setting, index) => ( + setOrgSetting(setting) + } + className={orgSetting === setting ? 'text-secondary' : ''} + > + {t(setting)} + + ))} + + + + + +
    +
    +
    + + {orgSetting === 'general' && ( + + + +
    +
    + {t('updateOrganization')} +
    +
    + + {orgId && } + +
    + + + + +
    +
    {t('otherSettings')}
    +
    + +
    + + {t('changeLanguage')} + + +
    +
    +
    + + + +
    +
    + {t('manageCustomFields')} +
    +
    + + {orgId && } + +
    + +
    + )} + + {orgSetting === 'actionItemCategories' && ( + +
    +
    + {t('actionItemCategories')} +
    +
    +
    + {orgId && } +
    +
    + )} +
    + + ); +} + +export default orgSettings; diff --git a/src/screens/OrganizationActionItems/ActionItemCreateModal.tsx b/src/screens/OrganizationActionItems/ActionItemCreateModal.tsx new file mode 100644 index 0000000000..88701077a6 --- /dev/null +++ b/src/screens/OrganizationActionItems/ActionItemCreateModal.tsx @@ -0,0 +1,155 @@ +import React from 'react'; +import { Modal, Form, Button } from 'react-bootstrap'; +import type { ChangeEvent } from 'react'; +import styles from './OrganizationActionItems.module.css'; +import { DatePicker } from '@mui/x-date-pickers'; +import dayjs from 'dayjs'; +import type { Dayjs } from 'dayjs'; + +import type { + InterfaceActionItemCategoryInfo, + InterfaceMemberInfo, +} from 'utils/interfaces'; + +interface InterfaceFormStateType { + actionItemCategoryId: string; + assigneeId: string; + eventId?: string; + preCompletionNotes: string; +} + +interface InterfaceActionItemCreateModalProps { + actionItemCreateModalIsOpen: boolean; + hideCreateModal: () => void; + formState: InterfaceFormStateType; + setFormState: (state: React.SetStateAction) => void; + createActionItemHandler: (e: ChangeEvent) => Promise; + t: (key: string) => string; + actionItemCategories: InterfaceActionItemCategoryInfo[] | undefined; + membersData: InterfaceMemberInfo[] | undefined; + dueDate: Date | null; + setDueDate: (state: React.SetStateAction) => void; +} + +const ActionItemCreateModal: React.FC = ({ + actionItemCreateModalIsOpen, + hideCreateModal, + formState, + setFormState, + createActionItemHandler, + t, + actionItemCategories, + membersData, + dueDate, + setDueDate, +}) => { + return ( + <> + + +

    {t('actionItemDetails')}

    + +
    + +
    + + {t('actionItemCategory')} + + setFormState({ + ...formState, + actionItemCategoryId: e.target.value, + }) + } + > + + {actionItemCategories?.map((category, index) => ( + + ))} + + + + + {t('assignee')} + + setFormState({ ...formState, assigneeId: e.target.value }) + } + > + + {membersData?.map((member, index) => ( + + ))} + + + + + { + setFormState({ + ...formState, + preCompletionNotes: e.target.value, + }); + }} + /> + +
    + { + if (date) { + setDueDate(date?.toDate()); + } + }} + /> +
    + + + +
    +
    + + ); +}; + +export default ActionItemCreateModal; diff --git a/src/screens/OrganizationActionItems/ActionItemDeleteModal.tsx b/src/screens/OrganizationActionItems/ActionItemDeleteModal.tsx new file mode 100644 index 0000000000..53b93ba9e5 --- /dev/null +++ b/src/screens/OrganizationActionItems/ActionItemDeleteModal.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import { Modal, Button } from 'react-bootstrap'; +import styles from './OrganizationActionItems.module.css'; + +interface InterfaceActionItemCreateModalProps { + actionItemDeleteModalIsOpen: boolean; + deleteActionItemHandler: () => Promise; + toggleDeleteModal: () => void; + t: (key: string) => string; + tCommon: (key: string) => string; +} + +const ActionItemPreviewModal: React.FC = ({ + actionItemDeleteModalIsOpen, + deleteActionItemHandler, + toggleDeleteModal, + t, + tCommon, +}) => { + return ( + <> + + + + {t('deleteActionItem')} + + + {t('deleteActionItemMsg')} + + + + + + + ); +}; + +export default ActionItemPreviewModal; diff --git a/src/screens/OrganizationActionItems/ActionItemPreviewModal.tsx b/src/screens/OrganizationActionItems/ActionItemPreviewModal.tsx new file mode 100644 index 0000000000..8f2d0b8f1c --- /dev/null +++ b/src/screens/OrganizationActionItems/ActionItemPreviewModal.tsx @@ -0,0 +1,133 @@ +import React from 'react'; +import { Modal, Form, Button } from 'react-bootstrap'; + +import styles from './OrganizationActionItems.module.css'; +import dayjs from 'dayjs'; + +interface InterfaceFormStateType { + assigneeId: string; + assignee: string; + assigner: string; + isCompleted: boolean; + preCompletionNotes: string; + postCompletionNotes: string; +} + +interface InterfaceActionItemCreateModalProps { + actionItemPreviewModalIsOpen: boolean; + hidePreviewModal: () => void; + showUpdateModal: () => void; + toggleDeleteModal: () => void; + formState: InterfaceFormStateType; + t: (key: string) => string; + dueDate: Date | null; + completionDate: Date | null; + assignmentDate: Date | null; +} + +const ActionItemPreviewModal: React.FC = ({ + actionItemPreviewModalIsOpen, + hidePreviewModal, + showUpdateModal, + toggleDeleteModal, + formState, + t, + dueDate, + completionDate, + assignmentDate, +}) => { + return ( + <> + + +

    {t('actionItemDetails')}

    + +
    + +
    +
    +

    + {t('assignee')}:{' '} + {formState.assignee} +

    +

    + {t('assigner')}:{' '} + {formState.assigner} +

    +

    + {t('preCompletionNotes')}: + + {formState.preCompletionNotes} + +

    +

    + {t('postCompletionNotes')}: + + {formState.postCompletionNotes} + +

    +

    + {t('assignmentDate')}:{' '} + + {dayjs(assignmentDate).format('YYYY-MM-DD')} + +

    +

    + {t('dueDate')}:{' '} + + {dayjs(dueDate).format('YYYY-MM-DD')} + +

    +

    + {t('completionDate')}:{' '} + + {dayjs(completionDate).format('YYYY-MM-DD')} + +

    +

    + {t('status')}:{' '} + + {formState.isCompleted ? 'Completed' : 'Active'} + +

    +
    +
    + + +
    +
    +
    +
    + + ); +}; + +export default ActionItemPreviewModal; diff --git a/src/screens/OrganizationActionItems/ActionItemUpdateModal.test.tsx b/src/screens/OrganizationActionItems/ActionItemUpdateModal.test.tsx new file mode 100644 index 0000000000..f52da23530 --- /dev/null +++ b/src/screens/OrganizationActionItems/ActionItemUpdateModal.test.tsx @@ -0,0 +1,235 @@ +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import ActionItemUpdateModal from './ActionItemUpdateModal'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import type { InterfaceMemberInfo } from 'utils/interfaces'; +import { t } from 'i18next'; + +const mockMembersData: InterfaceMemberInfo[] = [ + { + _id: '1', + firstName: 'John', + lastName: 'Doe', + email: 'john.doe@example.com', + image: 'https://example.com/john-doe.jpg', + createdAt: '2022-01-01T00:00:00.000Z', + organizationsBlockedBy: [], + }, + { + _id: '2', + firstName: 'Jane', + lastName: 'Smith', + email: 'jane.smith@example.com', + image: 'https://example.com/jane-smith.jpg', + createdAt: '2022-02-01T00:00:00.000Z', + organizationsBlockedBy: [], + }, +]; + +const mockFormState = { + assigneeId: '1', + assignee: 'John Doe', + assigner: 'Jane Smith', + isCompleted: false, + preCompletionNotes: 'Test pre-completion notes', + postCompletionNotes: '', +}; + +const mockDueDate = new Date('2023-05-01'); +const mockCompletionDate = new Date('2023-05-15'); + +const mockHideUpdateModal = jest.fn(); +const mockSetFormState = jest.fn(); +const mockUpdateActionItemHandler = jest.fn(); +const mockSetDueDate = jest.fn(); +const mockSetCompletionDate = jest.fn(); +const mockT = (key: string): string => key; + +describe('ActionItemUpdateModal', () => { + test('renders modal correctly', () => { + render( + + + + + + + + + + + , + ); + + expect(screen.getByText('actionItemDetails')).toBeInTheDocument(); + expect( + screen.getByTestId('updateActionItemModalCloseBtn'), + ).toBeInTheDocument(); + expect(screen.getByTestId('formUpdateAssignee')).toBeInTheDocument(); + expect(screen.getByLabelText('preCompletionNotes')).toBeInTheDocument(); + expect(screen.getByLabelText('dueDate')).toBeInTheDocument(); + expect(screen.getByLabelText('completionDate')).toBeInTheDocument(); + expect(screen.getByTestId('editActionItemBtn')).toBeInTheDocument(); + }); + + test('closes modal when close button is clicked', () => { + render( + + + + + + + + + + + , + ); + + fireEvent.click(screen.getByTestId('updateActionItemModalCloseBtn')); + expect(mockHideUpdateModal).toHaveBeenCalled(); + }); + + test('updates form state when assignee is changed', () => { + render( + + + + + + + + + + + , + ); + + const assigneeSelect = screen.getByTestId('formUpdateAssignee'); + userEvent.selectOptions(assigneeSelect, '2'); + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + assigneeId: '2', + }); + }); + + test('tests the condition for formState.preCompletionNotes', () => { + const mockFormState = { + assigneeId: '1', + assignee: 'John Doe', + assigner: 'Jane Smith', + isCompleted: false, + preCompletionNotes: '', + postCompletionNotes: '', + }; + render( + + + + + + + + + + + , + ); + const preCompletionNotesInput = screen.getByLabelText('preCompletionNotes'); + fireEvent.change(preCompletionNotesInput, { + target: { value: 'New pre-completion notes' }, + }); + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + preCompletionNotes: 'New pre-completion notes', + }); + }); + + test('calls updateActionItemHandler when form is submitted', () => { + render( + + + + + + + + + + + , + ); + + fireEvent.submit(screen.getByTestId('editActionItemBtn')); + expect(mockUpdateActionItemHandler).toHaveBeenCalled(); + }); +}); diff --git a/src/screens/OrganizationActionItems/ActionItemUpdateModal.tsx b/src/screens/OrganizationActionItems/ActionItemUpdateModal.tsx new file mode 100644 index 0000000000..8b0510a4dc --- /dev/null +++ b/src/screens/OrganizationActionItems/ActionItemUpdateModal.tsx @@ -0,0 +1,154 @@ +import React from 'react'; +import { Modal, Form, Button } from 'react-bootstrap'; +import type { ChangeEvent } from 'react'; +import { DatePicker } from '@mui/x-date-pickers'; +import dayjs from 'dayjs'; +import type { Dayjs } from 'dayjs'; + +import styles from './OrganizationActionItems.module.css'; +import type { InterfaceMemberInfo } from 'utils/interfaces'; + +interface InterfaceFormStateType { + assigneeId: string; + assignee: string; + assigner: string; + isCompleted: boolean; + preCompletionNotes: string; + postCompletionNotes: string; +} + +interface InterfaceActionItemCreateModalProps { + actionItemUpdateModalIsOpen: boolean; + hideUpdateModal: () => void; + formState: InterfaceFormStateType; + setFormState: (state: React.SetStateAction) => void; + updateActionItemHandler: (e: ChangeEvent) => Promise; + t: (key: string) => string; + membersData: InterfaceMemberInfo[] | undefined; + dueDate: Date | null; + setDueDate: (state: React.SetStateAction) => void; + completionDate: Date | null; + setCompletionDate: (state: React.SetStateAction) => void; +} + +const ActionItemUpdateModal: React.FC = ({ + actionItemUpdateModalIsOpen, + hideUpdateModal, + formState, + setFormState, + updateActionItemHandler, + t, + membersData, + dueDate, + setDueDate, + completionDate, + setCompletionDate, +}) => { + return ( + <> + + +

    {t('actionItemDetails')}

    + +
    + +
    + + {t('assignee')} + + setFormState({ ...formState, assigneeId: e.target.value }) + } + > + + {membersData?.map((member: InterfaceMemberInfo) => { + const currMemberName = `${member.firstName} ${member.lastName}`; + if (currMemberName !== formState.assignee) { + return ( + + ); + } + })} + + + + + { + setFormState({ + ...formState, + preCompletionNotes: e.target.value, + }); + }} + className="mb-2" + /> + +
    + { + /* istanbul ignore next */ + if (date) { + setDueDate(date?.toDate()); + } + } + } + /> +   + { + /* istanbul ignore next */ + if (date) { + setCompletionDate(date?.toDate()); + } + } + } + /> +
    + + + +
    +
    + + ); +}; + +export default ActionItemUpdateModal; diff --git a/src/screens/OrganizationActionItems/OrganizationActionItemMocks.ts b/src/screens/OrganizationActionItems/OrganizationActionItemMocks.ts new file mode 100644 index 0000000000..acbb243e5d --- /dev/null +++ b/src/screens/OrganizationActionItems/OrganizationActionItemMocks.ts @@ -0,0 +1,417 @@ +import { CREATE_ACTION_ITEM_MUTATION } from 'GraphQl/Mutations/mutations'; + +import { + ACTION_ITEM_CATEGORY_LIST, + ACTION_ITEM_LIST, + MEMBERS_LIST, +} from 'GraphQl/Queries/Queries'; + +export const MOCKS = [ + { + request: { + query: ACTION_ITEM_CATEGORY_LIST, + variables: { organizationId: '123' }, + }, + result: { + data: { + actionItemCategoriesByOrganization: [ + { + _id: 'actionItemCategory1', + name: 'ActionItemCategory 1', + isDisabled: false, + }, + ], + }, + }, + }, + { + request: { + query: MEMBERS_LIST, + variables: { id: '123' }, + }, + result: { + data: { + organizations: [ + { + _id: '123', + members: [ + { + _id: 'user1', + firstName: 'Harve', + lastName: 'Lance', + email: 'harve@example.com', + image: '', + organizationsBlockedBy: [], + createdAt: '2024-02-14', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: ACTION_ITEM_LIST, + variables: { + organizationId: '123', + orderBy: 'createdAt_DESC', + actionItemCategoryId: '', + isActive: false, + isCompleted: false, + }, + }, + result: { + data: { + actionItemsByOrganization: [ + { + _id: 'actionItem1', + assignee: { + _id: 'user1', + firstName: 'Harve', + lastName: 'Lance', + }, + actionItemCategory: { + _id: 'actionItemCategory1', + name: 'ActionItemCategory 1', + }, + preCompletionNotes: 'Pre Completion Notes', + postCompletionNotes: 'Post Completion Notes', + assignmentDate: '2024-02-14', + dueDate: '2024-02-21', + completionDate: '2024-02-21', + isCompleted: false, + assigner: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + event: { + _id: 'event1', + title: 'event 1', + }, + creator: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + { + _id: 'actionItem2', + assignee: { + _id: 'user2', + firstName: 'John', + lastName: 'Doe', + }, + actionItemCategory: { + _id: 'actionItemCategory2', + name: 'ActionItemCategory 2', + }, + preCompletionNotes: 'Pre Completion Notes', + postCompletionNotes: 'Post Completion Notes', + assignmentDate: '2024-02-14', + dueDate: '2024-02-21', + completionDate: '2024-02-21', + isCompleted: false, + assigner: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + event: null, + creator: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + ], + }, + }, + }, + { + request: { + query: ACTION_ITEM_LIST, + variables: { + organizationId: '123', + eventId: 'event1', + orderBy: 'createdAt_DESC', + }, + }, + result: { + data: { + actionItemsByOrganization: [ + { + _id: 'actionItem1', + assignee: { + _id: 'user1', + firstName: 'Harve', + lastName: 'Lance', + }, + actionItemCategory: { + _id: 'actionItemCategory1', + name: 'ActionItemCategory 1', + }, + preCompletionNotes: 'Pre Completion Notes', + postCompletionNotes: 'Post Completion Notes', + assignmentDate: '2024-02-14', + dueDate: '2024-02-21', + completionDate: '2024-02-21', + isCompleted: false, + assigner: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + event: { + _id: 'event1', + title: 'event 1', + }, + creator: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + ], + }, + }, + }, + { + request: { + query: ACTION_ITEM_LIST, + variables: { + organizationId: '123', + orderBy: 'createdAt_ASC', + actionItemCategoryId: '', + isActive: false, + isCompleted: false, + }, + }, + result: { + data: { + actionItemsByOrganization: [ + { + _id: 'actionItem3', + assignee: { + _id: 'user1', + firstName: 'Praise', + lastName: 'Norris', + }, + actionItemCategory: { + _id: 'actionItemCategory3', + name: 'ActionItemCategory 3', + }, + preCompletionNotes: 'Pre Completion Notes', + postCompletionNotes: 'Post Completion Notes', + assignmentDate: '2024-02-14', + dueDate: '2024-02-21', + completionDate: '2024-02-21', + isCompleted: false, + assigner: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + event: { + _id: 'event1', + title: 'event 1', + }, + creator: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + ], + }, + }, + }, + { + request: { + query: ACTION_ITEM_LIST, + variables: { + organizationId: '123', + orderBy: 'createdAt_ASC', + actionItemCategoryId: '', + isActive: true, + isCompleted: false, + }, + }, + result: { + data: { + actionItemsByOrganization: [ + { + _id: 'actionItem1', + assignee: { + _id: 'user1', + firstName: 'Harve', + lastName: 'Lance', + }, + actionItemCategory: { + _id: 'actionItemCategory1', + name: 'ActionItemCategory 1', + }, + preCompletionNotes: 'Pre Completion Notes', + postCompletionNotes: 'Post Completion Notes', + assignmentDate: '2024-02-14', + dueDate: '2024-02-21', + completionDate: '2024-02-21', + isCompleted: true, + assigner: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + event: { + _id: 'event1', + title: 'event 1', + }, + creator: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + ], + }, + }, + }, + { + request: { + query: ACTION_ITEM_LIST, + variables: { + organizationId: '123', + orderBy: 'createdAt_ASC', + actionItemCategoryId: '', + isActive: false, + isCompleted: true, + }, + }, + result: { + data: { + actionItemsByOrganization: [ + { + _id: 'actionItem1', + assignee: { + _id: 'user1', + firstName: 'Harve', + lastName: 'Lance', + }, + actionItemCategory: { + _id: 'actionItemCategory1', + name: 'ActionItemCategory 1', + }, + preCompletionNotes: 'Pre Completion Notes', + postCompletionNotes: 'Post Completion Notes', + assignmentDate: '2024-02-14', + dueDate: '2024-02-21', + completionDate: '2024-02-21', + isCompleted: true, + assigner: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + event: { + _id: 'event1', + title: 'event 1', + }, + creator: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + ], + }, + }, + }, + { + request: { + query: ACTION_ITEM_LIST, + variables: { + organizationId: '123', + orderBy: 'createdAt_ASC', + actionItemCategoryId: 'actionItemCategory1', + isActive: false, + isCompleted: true, + }, + }, + result: { + data: { + actionItemsByOrganization: [ + { + _id: 'actionItem1', + assignee: { + _id: 'user1', + firstName: 'Harve', + lastName: 'Lance', + }, + actionItemCategory: { + _id: 'actionItemCategory1', + name: 'ActionItemCategory 1', + }, + preCompletionNotes: 'Pre Completion Notes', + postCompletionNotes: 'Post Completion Notes', + assignmentDate: '2024-02-14', + dueDate: '2024-02-21', + completionDate: '2024-02-21', + isCompleted: true, + assigner: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + event: { + _id: 'event1', + title: 'event 1', + }, + creator: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + ], + }, + }, + }, + { + request: { + query: CREATE_ACTION_ITEM_MUTATION, + variables: { + actionItemCategoryId: 'actionItemCategory1', + assigneeId: 'user1', + preCompletionNotes: 'pre completion notes', + dueDate: '2024-02-14', + }, + }, + result: { + data: { + createActionItem: { + _id: 'actionItem2', + }, + }, + }, + }, + { + request: { + query: CREATE_ACTION_ITEM_MUTATION, + variables: { + eventId: 'event1', + actionItemCategoryId: 'actionItemCategory1', + assigneeId: 'user1', + preCompletionNotes: 'pre completion notes', + dueDate: '2024-02-14', + }, + }, + result: { + data: { + createActionItem: { + _id: 'actionItem2', + }, + }, + }, + }, +]; diff --git a/src/screens/OrganizationActionItems/OrganizationActionItems.module.css b/src/screens/OrganizationActionItems/OrganizationActionItems.module.css new file mode 100644 index 0000000000..7a67362c8b --- /dev/null +++ b/src/screens/OrganizationActionItems/OrganizationActionItems.module.css @@ -0,0 +1,168 @@ +.actionItemsContainer { + height: 90vh; +} + +.actionItemModal { + max-width: 80vw; + margin-top: 2vh; + margin-left: 13vw; +} + +.btnsContainer { + display: flex; + gap: 10px; +} + +.btnsContainer .btnsBlock { + display: flex; + gap: 10px; +} + +.btnsContainer button { + display: flex; + justify-content: center; + align-items: center; +} + +.container { + min-height: 100vh; +} + +.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; +} + +.dropdown { + display: block; +} + +.dropdownToggle { + margin-bottom: 0; + display: flex; +} + +.dropdownModalToggle { + width: 50%; +} + +.errorIcon { + transform: scale(1.5); + color: var(--bs-danger); + margin-bottom: 1rem; +} + +.greenregbtn { + margin: 1rem 0 0; + margin-top: 15px; + 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%; +} + +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; +} + +.organizationActionItemsContainer h2 { + margin: 0.6rem 0; +} + +.preview { + display: flex; + flex-direction: row; + font-weight: 900; + font-size: 16px; + color: rgb(80, 80, 80); +} + +.removeFilterIcon { + cursor: pointer; +} + +.searchForm { + display: inline; +} + +.titlemodal { + color: var(--bs-gray-600); + font-weight: 600; + font-size: 20px; + margin-bottom: 20px; + padding-bottom: 5px; + border-bottom: 3px solid var(--bs-primary); + width: 65%; +} + +.view { + margin-left: 2%; + font-weight: 600; + font-size: 16px; + color: var(--bs-gray-600); +} + +@media (max-width: 767px) { + .btnsContainer { + margin-bottom: 0; + display: flex; + flex-direction: column; + } + + .btnsContainer .btnsBlock .dropdownToggle { + flex-grow: 1; + } + + .btnsContainer button { + width: 100%; + } + + .createActionItemButton { + position: absolute; + top: 1rem; + right: 2rem; + } +} diff --git a/src/screens/OrganizationActionItems/OrganizationActionItems.test.tsx b/src/screens/OrganizationActionItems/OrganizationActionItems.test.tsx new file mode 100644 index 0000000000..7a9060a892 --- /dev/null +++ b/src/screens/OrganizationActionItems/OrganizationActionItems.test.tsx @@ -0,0 +1,619 @@ +import React from 'react'; +import { + render, + screen, + fireEvent, + waitFor, + act, + waitForElementToBeRemoved, +} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import 'jest-localstorage-mock'; +import { MockedProvider } from '@apollo/client/testing'; +import 'jest-location-mock'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import 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 OrganizationActionItems from './OrganizationActionItems'; +import { + MOCKS_ERROR_ACTION_ITEM_CATEGORY_LIST_QUERY, + MOCKS_ERROR_ACTION_ITEM_LIST_QUERY, + MOCKS_ERROR_MEMBERS_LIST_QUERY, + MOCKS_ERROR_MUTATIONS, +} from './OrganizationActionItemsErrorMocks'; +import { MOCKS } from './OrganizationActionItemMocks'; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +jest.mock('@mui/x-date-pickers/DateTimePicker', () => { + return { + DateTimePicker: jest.requireActual( + '@mui/x-date-pickers/DesktopDateTimePicker', + ).DesktopDateTimePicker, + }; +}); + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: '123' }), +})); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink( + MOCKS_ERROR_ACTION_ITEM_CATEGORY_LIST_QUERY, + true, +); +const link3 = new StaticMockLink(MOCKS_ERROR_MEMBERS_LIST_QUERY, true); +const link4 = new StaticMockLink(MOCKS_ERROR_ACTION_ITEM_LIST_QUERY, true); +const link5 = new StaticMockLink(MOCKS_ERROR_MUTATIONS, true); + +const translations = { + ...JSON.parse( + JSON.stringify( + i18n.getDataByLanguage('en')?.translation.organizationActionItems ?? {}, + ), + ), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), +}; + +describe('Testing Action Item Categories Component', () => { + const formData = { + actionItemCategory: 'ActionItemCategory 1', + assignee: 'Harve Lance', + preCompletionNotes: 'pre completion notes', + dueDate: '02/14/2024', + }; + + test('Component loads correctly', async () => { + const { getByText } = render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(getByText(translations.create)).toBeInTheDocument(); + }); + }); + + test('render error component on unsuccessful action item category list query', async () => { + const { queryByText } = render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(queryByText(translations.create)).not.toBeInTheDocument(); + }); + }); + + test('render error component on unsuccessful members list query', async () => { + const { queryByText } = render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(queryByText(translations.create)).not.toBeInTheDocument(); + }); + }); + + test('render error component on unsuccessful action item list query', async () => { + const { queryByText } = render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(queryByText(translations.create)).not.toBeInTheDocument(); + }); + }); + + test('sorts action items in earliest or latest first order based on orderBy', async () => { + render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('sortActionItems')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('sortActionItems')); + + await waitFor(() => { + expect(screen.getByTestId('earliest')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('earliest')); + + await waitFor(() => { + expect(screen.getByTestId('sortActionItems')).toHaveTextContent( + translations.earliest, + ); + }); + + await waitFor(() => { + expect(screen.getByTestId('sortActionItems')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('sortActionItems')); + + await waitFor(() => { + expect(screen.getByTestId('latest')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('latest')); + + await waitFor(() => { + expect(screen.getByTestId('sortActionItems')).toHaveTextContent( + translations.latest, + ); + }); + }); + + test('applies and then clears filters one by one', async () => { + render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('sortActionItems')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('sortActionItems')); + + await waitFor(() => { + expect(screen.getByTestId('earliest')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('earliest')); + + // all the action items ordered by earliest first + await waitFor(() => { + expect(screen.getByTestId('sortActionItems')).toHaveTextContent( + translations.earliest, + ); + }); + + await waitFor(() => { + expect(screen.getByTestId('selectActionItemStatus')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('selectActionItemStatus')); + + await waitFor(() => { + expect(screen.getByTestId('activeActionItems')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('activeActionItems')); + + // all the action items that are active + await waitFor(() => { + expect(screen.getByTestId('selectActionItemStatus')).toHaveTextContent( + translations.active, + ); + }); + + await waitFor(() => { + expect(screen.getByTestId('selectActionItemStatus')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('selectActionItemStatus')); + + await waitFor(() => { + expect(screen.getByTestId('completedActionItems')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('completedActionItems')); + + // all the action items that are completed + await waitFor(() => { + expect(screen.getByTestId('selectActionItemStatus')).toHaveTextContent( + translations.completed, + ); + }); + + await waitFor(() => { + expect( + screen.getByTestId('selectActionItemCategory'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('selectActionItemCategory')); + + await waitFor(() => { + expect( + screen.getAllByTestId('actionItemCategory')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('actionItemCategory')[0]); + + // action items belonging to this action item category + await waitFor(() => { + expect(screen.getByTestId('selectActionItemCategory')).toHaveTextContent( + 'ActionItemCategory 1', + ); + }); + + await waitFor(() => { + expect( + screen.getByTestId('clearActionItemCategoryFilter'), + ).toBeInTheDocument(); + }); + // remove the action item category filter + userEvent.click(screen.getByTestId('clearActionItemCategoryFilter')); + + await waitFor(() => { + expect( + screen.queryByTestId('clearActionItemCategoryFilter'), + ).not.toBeInTheDocument(); + }); + + await waitFor(() => { + expect( + screen.getByTestId('clearActionItemStatusFilter'), + ).toBeInTheDocument(); + }); + // remove the action item status filter + userEvent.click(screen.getByTestId('clearActionItemStatusFilter')); + + await waitFor(() => { + expect(screen.getByTestId('selectActionItemStatus')).toHaveTextContent( + translations.status, + ); + expect(screen.getByTestId('selectActionItemCategory')).toHaveTextContent( + translations.actionItemCategory, + ); + }); + }); + + test('applies and then clears all the filters', async () => { + render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('sortActionItems')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('sortActionItems')); + + await waitFor(() => { + expect(screen.getByTestId('earliest')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('earliest')); + + // all the action items ordered by earliest first + await waitFor(() => { + expect(screen.getByTestId('sortActionItems')).toHaveTextContent( + translations.earliest, + ); + }); + + await waitFor(() => { + expect(screen.getByTestId('selectActionItemStatus')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('selectActionItemStatus')); + + await waitFor(() => { + expect(screen.getByTestId('activeActionItems')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('activeActionItems')); + + // all the action items that are active + await waitFor(() => { + expect(screen.getByTestId('selectActionItemStatus')).toHaveTextContent( + translations.active, + ); + }); + + await waitFor(() => { + expect(screen.getByTestId('selectActionItemStatus')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('selectActionItemStatus')); + + await waitFor(() => { + expect(screen.getByTestId('completedActionItems')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('completedActionItems')); + + // all the action items that are completed + await waitFor(() => { + expect(screen.getByTestId('selectActionItemStatus')).toHaveTextContent( + translations.completed, + ); + }); + + await waitFor(() => { + expect( + screen.getByTestId('selectActionItemCategory'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('selectActionItemCategory')); + + await waitFor(() => { + expect( + screen.getAllByTestId('actionItemCategory')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('actionItemCategory')[0]); + + // action items belonging to this action item category + await waitFor(() => { + expect(screen.getByTestId('selectActionItemCategory')).toHaveTextContent( + 'ActionItemCategory 1', + ); + }); + + await waitFor(() => { + expect(screen.getByTestId('clearFilters')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('clearFilters')); + + // filters cleared, all the action items belonging to the organization + await waitFor(() => { + expect(screen.getByTestId('sortActionItems')).toHaveTextContent( + translations.latest, + ); + expect(screen.getByTestId('selectActionItemStatus')).toHaveTextContent( + translations.status, + ); + expect(screen.getByTestId('selectActionItemCategory')).toHaveTextContent( + translations.actionItemCategory, + ); + }); + }); + + test('opens and closes the create action item modal', async () => { + render( + + + + + + {} + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createActionItemBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('createActionItemBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('createActionItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('createActionItemModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('createActionItemModalCloseBtn'), + ); + }); + + test('creates new action item', async () => { + render( + + + + + + {} + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createActionItemBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('createActionItemBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('createActionItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + await waitFor(() => { + expect( + screen.getByTestId('formSelectActionItemCategory'), + ).toBeInTheDocument(); + }); + + userEvent.selectOptions( + screen.getByTestId('formSelectActionItemCategory'), + formData.actionItemCategory, + ); + + userEvent.selectOptions( + screen.getByTestId('formSelectAssignee'), + formData.assignee, + ); + + userEvent.type( + screen.getByPlaceholderText(translations.preCompletionNotes), + formData.preCompletionNotes, + ); + + const dueDatePicker = screen.getByLabelText(translations.dueDate); + fireEvent.change(dueDatePicker, { + target: { value: formData.dueDate }, + }); + + userEvent.click(screen.getByTestId('createActionItemFormSubmitBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.successfulCreation); + }); + }); + + test('toasts error on unsuccessful creation', async () => { + render( + + + + + + {} + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createActionItemBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('createActionItemBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('createActionItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + await waitFor(() => { + expect( + screen.getByTestId('formSelectActionItemCategory'), + ).toBeInTheDocument(); + }); + + userEvent.selectOptions( + screen.getByTestId('formSelectActionItemCategory'), + formData.actionItemCategory, + ); + + userEvent.selectOptions( + screen.getByTestId('formSelectAssignee'), + formData.assignee, + ); + + userEvent.type( + screen.getByPlaceholderText(translations.preCompletionNotes), + formData.preCompletionNotes, + ); + + const dueDatePicker = screen.getByLabelText(translations.dueDate); + fireEvent.change(dueDatePicker, { + target: { value: formData.dueDate }, + }); + + userEvent.click(screen.getByTestId('createActionItemFormSubmitBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); + + test('Testing Only Action Items Displaying', async () => { + const mockApp = render( + + + + + + {} + + + + + , + ); + + await waitFor(mockApp.asFragment); + + const actionItem = screen.getByText(/John Doe/i); + + expect(actionItem).toContainHTML('John Doe'); + }); +}); diff --git a/src/screens/OrganizationActionItems/OrganizationActionItems.tsx b/src/screens/OrganizationActionItems/OrganizationActionItems.tsx new file mode 100644 index 0000000000..4a863724fc --- /dev/null +++ b/src/screens/OrganizationActionItems/OrganizationActionItems.tsx @@ -0,0 +1,395 @@ +import React, { useState } from 'react'; +import type { ChangeEvent } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Button, Dropdown } from 'react-bootstrap'; +import { useParams } from 'react-router-dom'; + +import SortIcon from '@mui/icons-material/Sort'; +import { WarningAmberRounded } from '@mui/icons-material'; +import dayjs from 'dayjs'; +import { toast } from 'react-toastify'; + +import { useMutation, useQuery } from '@apollo/client'; +import { + ACTION_ITEM_CATEGORY_LIST, + ACTION_ITEM_LIST, + MEMBERS_LIST, +} from 'GraphQl/Queries/Queries'; +import { CREATE_ACTION_ITEM_MUTATION } from 'GraphQl/Mutations/mutations'; + +import type { + InterfaceActionItemCategoryList, + InterfaceActionItemList, + InterfaceMembersList, +} from 'utils/interfaces'; +import ActionItemsContainer from 'components/ActionItems/ActionItemsContainer'; +import ActionItemCreateModal from './ActionItemCreateModal'; +import styles from './OrganizationActionItems.module.css'; +import Loader from 'components/Loader/Loader'; + +function organizationActionItems(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'organizationActionItems', + }); + const { t: tCommon } = useTranslation('common'); + + const { orgId: currentUrl } = useParams(); + + const [actionItemCreateModalIsOpen, setActionItemCreateModalIsOpen] = + useState(false); + const [dueDate, setDueDate] = useState(new Date()); + const [orderBy, setOrderBy] = useState<'Latest' | 'Earliest'>('Latest'); + const [actionItemStatus, setActionItemStatus] = useState(''); + const [actionItemCategoryId, setActionItemCategoryId] = useState(''); + const [actionItemCategoryName, setActionItemCategoryName] = useState(''); + + const [formState, setFormState] = useState({ + actionItemCategoryId: '', + assigneeId: '', + preCompletionNotes: '', + }); + + const { + data: actionItemCategoriesData, + loading: actionItemCategoriesLoading, + error: actionItemCategoriesError, + }: { + data: InterfaceActionItemCategoryList | undefined; + loading: boolean; + error?: Error | undefined; + } = useQuery(ACTION_ITEM_CATEGORY_LIST, { + variables: { + organizationId: currentUrl, + }, + notifyOnNetworkStatusChange: true, + }); + + const { + data: membersData, + loading: membersLoading, + error: membersError, + }: { + data: InterfaceMembersList | undefined; + loading: boolean; + error?: Error | undefined; + } = useQuery(MEMBERS_LIST, { + variables: { id: currentUrl }, + }); + + const { + data: actionItemsData, + loading: actionItemsLoading, + error: actionItemsError, + refetch: actionItemsRefetch, + }: { + data: InterfaceActionItemList | undefined; + loading: boolean; + error?: Error | undefined; + refetch: () => void; + } = useQuery(ACTION_ITEM_LIST, { + variables: { + organizationId: currentUrl, + actionItemCategoryId, + orderBy: orderBy === 'Latest' ? 'createdAt_DESC' : 'createdAt_ASC', + isActive: actionItemStatus === 'Active' ? true : false, + isCompleted: actionItemStatus === 'Completed' ? true : false, + }, + notifyOnNetworkStatusChange: true, + }); + + const [createActionItem] = useMutation(CREATE_ACTION_ITEM_MUTATION); + + const createActionItemHandler = async ( + e: ChangeEvent, + ): Promise => { + e.preventDefault(); + try { + await createActionItem({ + variables: { + assigneeId: formState.assigneeId, + actionItemCategoryId: formState.actionItemCategoryId, + preCompletionNotes: formState.preCompletionNotes, + dueDate: dayjs(dueDate).format('YYYY-MM-DD'), + }, + }); + + setFormState({ + assigneeId: '', + actionItemCategoryId: '', + preCompletionNotes: '', + }); + + setDueDate(new Date()); + + actionItemsRefetch(); + hideCreateModal(); + toast.success(t('successfulCreation')); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + console.log(error.message); + } + } + }; + + const showCreateModal = (): void => { + setActionItemCreateModalIsOpen(!actionItemCreateModalIsOpen); + }; + + const hideCreateModal = (): void => { + setActionItemCreateModalIsOpen(!actionItemCreateModalIsOpen); + }; + + const handleSorting = (sort: string): void => { + if (sort === 'Latest') { + setOrderBy('Latest'); + } else { + setOrderBy('Earliest'); + } + }; + + const handleStatusFilter = (status: string): void => { + if (status === 'Active') { + setActionItemStatus('Active'); + } else { + setActionItemStatus('Completed'); + } + }; + + const handleClearFilters = (): void => { + setActionItemCategoryId(''); + setActionItemCategoryName(''); + setActionItemStatus(''); + setOrderBy('Latest'); + }; + + if (actionItemCategoriesLoading || membersLoading || actionItemsLoading) { + return ; + } + + if (actionItemCategoriesError || membersError || actionItemsError) { + return ( +
    +
    + +
    + Error occured while loading{' '} + {actionItemCategoriesError + ? 'Action Item Categories' + : membersError + ? 'Members List' + : 'Action Items List'}{' '} + Data +
    + {actionItemCategoriesError + ? actionItemCategoriesError.message + : membersError + ? membersError.message + : actionItemsError?.message} +
    +
    +
    + ); + } + + const actionItemCategories = + actionItemCategoriesData?.actionItemCategoriesByOrganization.filter( + (category) => !category.isDisabled, + ); + + const actionItemOnly = actionItemsData?.actionItemsByOrganization.filter( + (item) => item.event == null, + ); + + return ( +
    +
    +
    +
    +
    + + + + + +
    + +
    + {!actionItemCategoryName && !actionItemStatus && ( +
    + {tCommon('noFiltersApplied')} +
    + )} + + {actionItemCategoryName !== '' && ( +
    + {actionItemCategoryName} + { + setActionItemCategoryName(''); + setActionItemCategoryId(''); + }} + data-testid="clearActionItemCategoryFilter" + /> +
    + )} + + {actionItemStatus !== '' && ( +
    + {actionItemStatus} + setActionItemStatus('')} + data-testid="clearActionItemStatusFilter" + /> +
    + )} +
    + + + +
    +
    + +
    + + +
    + + {/* Create Modal */} + +
    + ); +} + +export default organizationActionItems; diff --git a/src/screens/OrganizationActionItems/OrganizationActionItemsErrorMocks.ts b/src/screens/OrganizationActionItems/OrganizationActionItemsErrorMocks.ts new file mode 100644 index 0000000000..bedba6572b --- /dev/null +++ b/src/screens/OrganizationActionItems/OrganizationActionItemsErrorMocks.ts @@ -0,0 +1,266 @@ +import { CREATE_ACTION_ITEM_MUTATION } from 'GraphQl/Mutations/mutations'; + +import { + ACTION_ITEM_CATEGORY_LIST, + ACTION_ITEM_LIST, + MEMBERS_LIST, +} from 'GraphQl/Queries/Queries'; + +export const MOCKS_ERROR_ACTION_ITEM_CATEGORY_LIST_QUERY = [ + { + request: { + query: ACTION_ITEM_CATEGORY_LIST, + variables: { organizationId: '123' }, + }, + error: new Error('Mock Graphql Error'), + }, +]; + +export const MOCKS_ERROR_MEMBERS_LIST_QUERY = [ + { + request: { + query: ACTION_ITEM_CATEGORY_LIST, + variables: { organizationId: '123' }, + }, + result: { + data: { + actionItemCategoriesByOrganization: [ + { + _id: 'actionItemCategory1', + name: 'ActionItemCategory 1', + isDisabled: false, + }, + ], + }, + }, + }, + { + request: { + query: MEMBERS_LIST, + variables: { id: '123' }, + }, + error: new Error('Mock Graphql Error'), + }, +]; + +export const MOCKS_ERROR_ACTION_ITEM_LIST_QUERY = [ + { + request: { + query: ACTION_ITEM_CATEGORY_LIST, + variables: { organizationId: '123' }, + }, + result: { + data: { + actionItemCategoriesByOrganization: [ + { + _id: 'actionItemCategory1', + name: 'ActionItemCategory 1', + isDisabled: false, + }, + ], + }, + }, + }, + { + request: { + query: MEMBERS_LIST, + variables: { id: '123' }, + }, + result: { + data: { + organizations: [ + { + _id: '123', + members: [ + { + _id: 'user1', + firstName: 'Harve', + lastName: 'Lance', + email: 'harve@example.com', + image: '', + organizationsBlockedBy: [], + createdAt: '2024-02-14', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: ACTION_ITEM_LIST, + variables: { id: '123' }, + }, + error: new Error('Mock Graphql Error'), + }, +]; + +export const MOCKS_ERROR_MUTATIONS = [ + { + request: { + query: ACTION_ITEM_CATEGORY_LIST, + variables: { organizationId: '123' }, + }, + result: { + data: { + actionItemCategoriesByOrganization: [ + { + _id: 'actionItemCategory1', + name: 'ActionItemCategory 1', + isDisabled: false, + }, + ], + }, + }, + }, + { + request: { + query: MEMBERS_LIST, + variables: { id: '123' }, + }, + result: { + data: { + organizations: [ + { + _id: '123', + members: [ + { + _id: 'user1', + firstName: 'Harve', + lastName: 'Lance', + email: 'harve@example.com', + image: '', + organizationsBlockedBy: [], + createdAt: '2024-02-14', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: ACTION_ITEM_LIST, + variables: { + organizationId: '123', + orderBy: 'createdAt_DESC', + actionItemCategoryId: '', + isActive: false, + isCompleted: false, + }, + }, + result: { + data: { + actionItemsByOrganization: [ + { + _id: 'actionItem1', + assignee: { + _id: 'user1', + firstName: 'Harve', + lastName: 'Lance', + }, + actionItemCategory: { + _id: 'actionItemCategory1', + name: 'ActionItemCategory 1', + }, + preCompletionNotes: 'Pre Completion Notes', + postCompletionNotes: 'Post Completion Notes', + assignmentDate: '2024-02-14', + dueDate: '2024-02-21', + completionDate: '2024-02-21', + isCompleted: false, + assigner: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + event: { + _id: 'event1', + title: 'event 1', + }, + creator: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + ], + }, + }, + }, + { + request: { + query: ACTION_ITEM_LIST, + variables: { + organizationId: '123', + eventId: 'event1', + orderBy: 'createdAt_DESC', + }, + }, + result: { + data: { + actionItemsByOrganization: [ + { + _id: 'actionItem1', + assignee: { + _id: 'user1', + firstName: 'Harve', + lastName: 'Lance', + }, + actionItemCategory: { + _id: 'actionItemCategory1', + name: 'ActionItemCategory 1', + }, + preCompletionNotes: 'Pre Completion Notes', + postCompletionNotes: 'Post Completion Notes', + assignmentDate: '2024-02-14', + dueDate: '2024-02-21', + completionDate: '2024-02-21', + isCompleted: false, + assigner: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + event: { + _id: 'event1', + title: 'event 1', + }, + creator: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + ], + }, + }, + }, + { + request: { + query: CREATE_ACTION_ITEM_MUTATION, + variables: { + actionItemCategoryId: 'actionItemCategory1', + assigneeId: 'user1', + preCompletionNotes: 'pre completion notes', + dueDate: '2024-02-14', + }, + }, + error: new Error('Mock Graphql Error'), + }, + { + request: { + query: CREATE_ACTION_ITEM_MUTATION, + variables: { + eventId: 'event1', + actionItemCategoryId: 'actionItemCategory1', + assigneeId: 'user1', + preCompletionNotes: 'pre completion notes', + dueDate: '2024-02-14', + }, + }, + error: new Error('Mock Graphql Error'), + }, +]; diff --git a/src/screens/OrganizationAgendaCategory/AgendaCategoryCreateModal.test.tsx b/src/screens/OrganizationAgendaCategory/AgendaCategoryCreateModal.test.tsx new file mode 100644 index 0000000000..da92dfd201 --- /dev/null +++ b/src/screens/OrganizationAgendaCategory/AgendaCategoryCreateModal.test.tsx @@ -0,0 +1,125 @@ +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; + +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; + +import AgendaCategoryCreateModal from './AgendaCategoryCreateModal'; + +const mockFormState = { + name: 'Test Name', + description: 'Test Description', + createdBy: 'Test User', +}; +const mockHideCreateModal = jest.fn(); +const mockSetFormState = jest.fn(); +const mockCreateAgendaCategoryHandler = jest.fn(); +const mockT = (key: string): string => key; + +describe('AgendaCategoryCreateModal', () => { + test('renders modal correctly', () => { + render( + + + + + + + + + + + , + ); + + expect(screen.getByText('agendaCategoryDetails')).toBeInTheDocument(); + expect( + screen.getByTestId('createAgendaCategoryFormSubmitBtn'), + ).toBeInTheDocument(); + expect( + screen.getByTestId('createAgendaCategoryModalCloseBtn'), + ).toBeInTheDocument(); + }); + test('tests the condition for formState.name and formState.description', () => { + const mockFormState = { + name: 'Test Name', + description: 'Test Description', + createdBy: 'Test User', + }; + render( + + + + + + + + + + + , + ); + const nameInput = screen.getByLabelText('name'); + fireEvent.change(nameInput, { + target: { value: 'New name' }, + }); + const descriptionInput = screen.getByLabelText('description'); + fireEvent.change(descriptionInput, { + target: { value: 'New description' }, + }); + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + name: 'New name', + }); + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + description: 'New description', + }); + }); + test('calls createAgendaCategoryHandler when form is submitted', () => { + render( + + + + + + + + + + + , + ); + + fireEvent.submit(screen.getByTestId('createAgendaCategoryFormSubmitBtn')); + expect(mockCreateAgendaCategoryHandler).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/screens/OrganizationAgendaCategory/AgendaCategoryCreateModal.tsx b/src/screens/OrganizationAgendaCategory/AgendaCategoryCreateModal.tsx new file mode 100644 index 0000000000..9b260d877f --- /dev/null +++ b/src/screens/OrganizationAgendaCategory/AgendaCategoryCreateModal.tsx @@ -0,0 +1,89 @@ +import React from 'react'; +import { Modal, Form, Button } from 'react-bootstrap'; +import type { ChangeEvent } from 'react'; +import styles from './OrganizationAgendaCategory.module.css'; + +interface InterfaceFormStateType { + name: string; + description: string; + createdBy: string; +} + +interface InterfaceAgendaCategoryCreateModalProps { + agendaCategoryCreateModalIsOpen: boolean; + hideCreateModal: () => void; + formState: InterfaceFormStateType; + setFormState: (state: React.SetStateAction) => void; + createAgendaCategoryHandler: ( + e: ChangeEvent, + ) => Promise; + t: (key: string) => string; +} + +const AgendaCategoryCreateModal: React.FC< + InterfaceAgendaCategoryCreateModalProps +> = ({ + agendaCategoryCreateModalIsOpen, + hideCreateModal, + formState, + setFormState, + createAgendaCategoryHandler, + t, +}) => { + return ( + + +

    {t('agendaCategoryDetails')}

    + +
    + +
    + + {t('name')} + + setFormState({ ...formState, name: e.target.value }) + } + /> + + + {t('description')} + + setFormState({ ...formState, description: e.target.value }) + } + /> + + +
    +
    +
    + ); +}; + +export default AgendaCategoryCreateModal; diff --git a/src/screens/OrganizationAgendaCategory/AgendaCategoryDeleteModal.tsx b/src/screens/OrganizationAgendaCategory/AgendaCategoryDeleteModal.tsx new file mode 100644 index 0000000000..f2edb8fc62 --- /dev/null +++ b/src/screens/OrganizationAgendaCategory/AgendaCategoryDeleteModal.tsx @@ -0,0 +1,63 @@ +import React from 'react'; +import { Modal, Button } from 'react-bootstrap'; +import styles from './OrganizationAgendaCategory.module.css'; + +interface InterfaceAgendaCategoryDeleteModalProps { + agendaCategoryDeleteModalIsOpen: boolean; + toggleDeleteModal: () => void; + deleteAgendaCategoryHandler: () => Promise; + t: (key: string) => string; + tCommon: (key: string) => string; +} + +const AgendaCategoryDeleteModal: React.FC< + InterfaceAgendaCategoryDeleteModalProps +> = ({ + agendaCategoryDeleteModalIsOpen, + toggleDeleteModal, + deleteAgendaCategoryHandler, + t, + tCommon, +}) => { + return ( + + + + {t('deleteAgendaCategory')} + + + +

    {t('deleteAgendaCategoryMsg')}

    +
    + + + + +
    + ); +}; + +export default AgendaCategoryDeleteModal; diff --git a/src/screens/OrganizationAgendaCategory/AgendaCategoryPreviewModal.tsx b/src/screens/OrganizationAgendaCategory/AgendaCategoryPreviewModal.tsx new file mode 100644 index 0000000000..c9dc17e56f --- /dev/null +++ b/src/screens/OrganizationAgendaCategory/AgendaCategoryPreviewModal.tsx @@ -0,0 +1,91 @@ +import React from 'react'; +import { Modal, Form, Button } from 'react-bootstrap'; + +import styles from './OrganizationAgendaCategory.module.css'; + +interface InterfaceFormStateType { + name: string; + description: string; + createdBy: string; +} + +interface InterfaceAgendaCategoryPreviewModalProps { + agendaCategoryPreviewModalIsOpen: boolean; + hidePreviewModal: () => void; + showUpdateModal: () => void; + toggleDeleteModal: () => void; + formState: InterfaceFormStateType; + + t: (key: string) => string; +} + +const AgendaCategoryPreviewModal: React.FC< + InterfaceAgendaCategoryPreviewModalProps +> = ({ + agendaCategoryPreviewModalIsOpen, + hidePreviewModal, + showUpdateModal, + toggleDeleteModal, + formState, + t, +}) => { + return ( + + +

    {t('agendaCategoryDetails')}

    + +
    + +
    +
    +

    + {t('name')} + {formState.name} +

    +

    + {t('description')} + {formState.description} +

    +

    + {t('createdBy')} + {formState.createdBy} +

    +
    +
    + + +
    +
    +
    +
    + ); +}; + +export default AgendaCategoryPreviewModal; diff --git a/src/screens/OrganizationAgendaCategory/AgendaCategoryUpdateModal.test.tsx b/src/screens/OrganizationAgendaCategory/AgendaCategoryUpdateModal.test.tsx new file mode 100644 index 0000000000..168b97abd3 --- /dev/null +++ b/src/screens/OrganizationAgendaCategory/AgendaCategoryUpdateModal.test.tsx @@ -0,0 +1,151 @@ +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; + +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; + +import AgendaCategoryUpdateModal from './AgendaCategoryUpdateModal'; + +const mockFormState = { + name: 'Test Name', + description: 'Test Description', + createdBy: 'Test User', +}; +const mockHideUpdateModal = jest.fn(); +const mockSetFormState = jest.fn(); +const mockUpdateAgendaCategoryHandler = jest.fn(); +const mockT = (key: string): string => key; + +describe('AgendaCategoryUpdateModal', () => { + test('renders modal correctly', () => { + render( + + + + + + + + + + + , + ); + + expect(screen.getByText('updateAgendaCategory')).toBeInTheDocument(); + expect(screen.getByTestId('editAgendaCategoryBtn')).toBeInTheDocument(); + expect( + screen.getByTestId('updateAgendaCategoryModalCloseBtn'), + ).toBeInTheDocument(); + }); + + test('calls hideUpdateModal when close button is clicked', () => { + render( + + + + + + + + + + + , + ); + + userEvent.click(screen.getByTestId('updateAgendaCategoryModalCloseBtn')); + expect(mockHideUpdateModal).toHaveBeenCalledTimes(1); + }); + + test('tests the condition for formState.name and formState.description', () => { + const mockFormState = { + name: 'Test Name', + description: 'Test Description', + createdBy: 'Test User', + }; + render( + + + + + + + + + + + , + ); + const nameInput = screen.getByLabelText('name'); + fireEvent.change(nameInput, { + target: { value: 'New name' }, + }); + const descriptionInput = screen.getByLabelText('description'); + fireEvent.change(descriptionInput, { + target: { value: 'New description' }, + }); + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + name: 'New name', + }); + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + description: 'New description', + }); + }); + + test('calls updateAgendaCategoryHandler when form is submitted', () => { + render( + + + + + + + + + + + , + ); + + fireEvent.submit(screen.getByTestId('editAgendaCategoryBtn')); + expect(mockUpdateAgendaCategoryHandler).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/screens/OrganizationAgendaCategory/AgendaCategoryUpdateModal.tsx b/src/screens/OrganizationAgendaCategory/AgendaCategoryUpdateModal.tsx new file mode 100644 index 0000000000..868205c339 --- /dev/null +++ b/src/screens/OrganizationAgendaCategory/AgendaCategoryUpdateModal.tsx @@ -0,0 +1,86 @@ +import React from 'react'; +import { Modal, Form, Button } from 'react-bootstrap'; +import type { ChangeEvent } from 'react'; + +import styles from './OrganizationAgendaCategory.module.css'; + +interface InterfaceFormStateType { + name: string; + description: string; + createdBy: string; +} + +interface InterfaceAgendaCategoryUpdateModalProps { + agendaCategoryUpdateModalIsOpen: boolean; + hideUpdateModal: () => void; + formState: InterfaceFormStateType; + setFormState: (state: React.SetStateAction) => void; + updateAgendaCategoryHandler: ( + e: ChangeEvent, + ) => Promise; + t: (key: string) => string; +} + +const AgendaCategoryUpdateModal: React.FC< + InterfaceAgendaCategoryUpdateModalProps +> = ({ + agendaCategoryUpdateModalIsOpen, + hideUpdateModal, + formState, + setFormState, + updateAgendaCategoryHandler, + t, +}) => { + return ( + + +

    {t('updateAgendaCategory')}

    + +
    + +
    + + {t('name')} + + setFormState({ ...formState, name: e.target.value }) + } + /> + + + {t('description')} + + setFormState({ ...formState, description: e.target.value }) + } + /> + + +
    +
    +
    + ); +}; + +export default AgendaCategoryUpdateModal; diff --git a/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategory.module.css b/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategory.module.css new file mode 100644 index 0000000000..13e187f8b5 --- /dev/null +++ b/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategory.module.css @@ -0,0 +1,171 @@ +.agendaCategoryContainer { + height: 90vh; +} + +.agendaCategoryModal { + max-width: 80vw; + margin-top: 2vh; + margin-left: 13vw; +} + +.btnsContainer { + display: flex; + gap: 10px; +} + +.btnsContainer .btnsBlock { + display: flex; + gap: 10px; +} + +.btnsContainer button { + display: flex; + align-items: center; +} + +.container { + min-height: 100vh; +} + +.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; +} + +.dropdown { + display: block; +} + +.dropdownToggle { + margin-bottom: 0; + display: flex; +} + +.dropdownModalToggle { + width: 50%; +} + +.errorIcon { + transform: scale(1.5); + color: var(--bs-danger); + margin-bottom: 1rem; +} + +.greenregbtn { + margin: 1rem 0 0; + margin-top: 15px; + 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%; +} + +h2 { + margin-top: 0.5rem; +} + +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; +} + +.organizationAgendaCategoryContainer h2 { + margin: 0.6rem 0; +} + +.preview { + display: flex; + flex-direction: row; + font-weight: 900; + font-size: 16px; + color: rgb(80, 80, 80); +} + +.removeFilterIcon { + cursor: pointer; +} + +.searchForm { + display: inline; +} + +.titlemodal { + color: var(--bs-gray-600); + font-weight: 600; + font-size: 20px; + margin-bottom: 20px; + padding-bottom: 5px; + border-bottom: 3px solid var(--bs-primary); + width: 65%; +} + +.view { + margin-left: 2%; + font-weight: 600; + font-size: 16px; + color: var(--bs-gray-600); +} + +@media (max-width: 767px) { + .btnsContainer { + margin-bottom: 0; + display: flex; + flex-direction: column; + } + + .btnsContainer .btnsBlock .dropdownToggle { + flex-grow: 1; + } + + .btnsContainer button { + width: 100%; + } + + .createAgendaCategoryButton { + position: absolute; + top: 1rem; + right: 2rem; + } +} diff --git a/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategory.test.tsx b/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategory.test.tsx new file mode 100644 index 0000000000..732db13a74 --- /dev/null +++ b/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategory.test.tsx @@ -0,0 +1,235 @@ +import React from 'react'; +import { + render, + screen, + waitFor, + act, + waitForElementToBeRemoved, +} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import 'jest-localstorage-mock'; +import { MockedProvider } from '@apollo/client/testing'; +import 'jest-location-mock'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import i18n from 'utils/i18nForTest'; +import { toast } from 'react-toastify'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; + +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; + +import OrganizationAgendaCategory from './OrganizationAgendaCategory'; +import { + MOCKS_ERROR_AGENDA_ITEM_CATEGORY_LIST_QUERY, + MOCKS_ERROR_MUTATION, +} from './OrganizationAgendaCategoryErrorMocks'; +import { MOCKS } from './OrganizationAgendaCategoryMocks'; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: '123' }), +})); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink( + MOCKS_ERROR_AGENDA_ITEM_CATEGORY_LIST_QUERY, + true, +); +const link3 = new StaticMockLink(MOCKS_ERROR_MUTATION, true); + +const translations = { + ...JSON.parse( + JSON.stringify( + i18n.getDataByLanguage('en')?.translation.organizationAgendaCategory ?? + {}, + ), + ), +}; + +describe('Testing Agenda Categories Component', () => { + const formData = { + name: 'Category', + description: 'Test Description', + createdBy: 'Test User', + }; + test('Component loads correctly', async () => { + const { getByText } = render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(getByText(translations.createAgendaCategory)).toBeInTheDocument(); + }); + }); + + test('render error component on unsuccessful agenda category list query', async () => { + const { queryByText } = render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + queryByText(translations.createAgendaCategory), + ).not.toBeInTheDocument(); + }); + }); + + test('opens and closes the create agenda category modal', async () => { + render( + + + + + + {} + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createAgendaCategoryBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('createAgendaCategoryBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('createAgendaCategoryModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('createAgendaCategoryModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('createAgendaCategoryModalCloseBtn'), + ); + }); + test('creates new agenda cagtegory', async () => { + render( + + + + + + {} + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createAgendaCategoryBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('createAgendaCategoryBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('createAgendaCategoryModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + userEvent.type( + screen.getByPlaceholderText(translations.name), + formData.name, + ); + + userEvent.type( + screen.getByPlaceholderText(translations.description), + formData.description, + ); + userEvent.click(screen.getByTestId('createAgendaCategoryFormSubmitBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.agendaCategoryCreated); + }); + }); + + // test('toasts error on unsuccessful creation', async () => { + // render( + // + // + // + // + // + // {} + // + // + // + // + // , + // ); + + // await wait(); + + // await waitFor(() => { + // expect(screen.getByTestId('createAgendaCategoryBtn')).toBeInTheDocument(); + // }); + // userEvent.click(screen.getByTestId('createAgendaCategoryBtn')); + + // await waitFor(() => { + // return expect( + // screen.findByTestId('createAgendaCategoryModalCloseBtn'), + // ).resolves.toBeInTheDocument(); + // }); + + // userEvent.type( + // screen.getByPlaceholderText(translations.name), + // formData.name, + // ); + + // userEvent.type( + // screen.getByPlaceholderText(translations.description), + // formData.description, + // ); + // userEvent.click(screen.getByTestId('createAgendaCategoryFormSubmitBtn')); + + // await waitFor(() => { + // expect(toast.error).toBeCalledWith(); + // }); + // }); +}); diff --git a/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategory.tsx b/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategory.tsx new file mode 100644 index 0000000000..4216d309a2 --- /dev/null +++ b/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategory.tsx @@ -0,0 +1,157 @@ +import React, { useState } from 'react'; +import type { ChangeEvent } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Button } from 'react-bootstrap'; +import { useParams } from 'react-router-dom'; + +import { WarningAmberRounded } from '@mui/icons-material'; +import { toast } from 'react-toastify'; + +import { useMutation, useQuery } from '@apollo/client'; +import { AGENDA_ITEM_CATEGORY_LIST } from 'GraphQl/Queries/Queries'; +import { CREATE_AGENDA_ITEM_CATEGORY_MUTATION } from 'GraphQl/Mutations/mutations'; + +import type { InterfaceAgendaItemCategoryList } from 'utils/interfaces'; +import AgendaCategoryContainer from 'components/AgendaCategory/AgendaCategoryContainer'; +import AgendaCategoryCreateModal from './AgendaCategoryCreateModal'; +import styles from './OrganizationAgendaCategory.module.css'; +import Loader from 'components/Loader/Loader'; + +function organizationAgendaCategory(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'organizationAgendaCategory', + }); + + const { orgId: currentUrl } = useParams(); + + const [agendaCategoryCreateModalIsOpen, setAgendaCategoryCreateModalIsOpen] = + useState(false); + + const [formState, setFormState] = useState({ + name: '', + description: '', + createdBy: '', + }); + + const { + data: agendaCategoryData, + loading: agendaCategoryLoading, + error: agendaCategoryError, + refetch: refetchAgendaCategory, + }: { + data: InterfaceAgendaItemCategoryList | undefined; + loading: boolean; + error?: unknown | undefined; + refetch: () => void; + } = useQuery(AGENDA_ITEM_CATEGORY_LIST, { + variables: { organizationId: currentUrl }, + notifyOnNetworkStatusChange: true, + }); + + const [createAgendaCategory] = useMutation( + CREATE_AGENDA_ITEM_CATEGORY_MUTATION, + ); + + const createAgendaCategoryHandler = async ( + e: ChangeEvent, + ): Promise => { + e.preventDefault(); + try { + await createAgendaCategory({ + variables: { + input: { + organizationId: currentUrl, + name: formState.name, + description: formState.description, + }, + }, + }); + toast.success(t('agendaCategoryCreated')); + setFormState({ name: '', description: '', createdBy: '' }); + refetchAgendaCategory(); + hideCreateModal(); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + } + } + }; + + const showCreateModal = (): void => { + setAgendaCategoryCreateModalIsOpen(!agendaCategoryCreateModalIsOpen); + }; + + const hideCreateModal = (): void => { + setAgendaCategoryCreateModalIsOpen(!agendaCategoryCreateModalIsOpen); + }; + + if (agendaCategoryLoading) return ; + + if (agendaCategoryError) { + return ( +
    +
    + +
    + Error occured while loading{' '} + {agendaCategoryError && 'Agenda Categories'} + Data +
    + {agendaCategoryError && (agendaCategoryError as Error).message} +
    +
    +
    + ); + } + + return ( +
    +
    +
    +
    +
    + {/* setSearchValue(e.target.value)} + value={searchValue} + data-testid="searchAgendaCategories" + /> */} +
    + + +
    +
    + +
    + + +
    + +
    + ); +} + +export default organizationAgendaCategory; diff --git a/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategoryErrorMocks.ts b/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategoryErrorMocks.ts new file mode 100644 index 0000000000..10809c3da8 --- /dev/null +++ b/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategoryErrorMocks.ts @@ -0,0 +1,51 @@ +import { CREATE_AGENDA_ITEM_CATEGORY_MUTATION } from 'GraphQl/Mutations/AgendaCategoryMutations'; + +import { AGENDA_ITEM_CATEGORY_LIST } from 'GraphQl/Queries/AgendaCategoryQueries'; + +export const MOCKS_ERROR_AGENDA_ITEM_CATEGORY_LIST_QUERY = [ + { + request: { + query: AGENDA_ITEM_CATEGORY_LIST, + variables: { organizationId: '123' }, + }, + error: new Error('Mock Graphql Error'), + }, +]; + +export const MOCKS_ERROR_MUTATION = [ + { + request: { + query: AGENDA_ITEM_CATEGORY_LIST, + variables: { organizationId: '123' }, + }, + result: { + data: { + agendaItemCategoriesByOrganization: [ + { + _id: 'agendaItemCategory1', + name: 'Category', + description: 'Test Description', + createdBy: { + _id: 'user1', + firstName: 'Harve', + lastName: 'Lance', + }, + }, + ], + }, + }, + }, + { + request: { + query: CREATE_AGENDA_ITEM_CATEGORY_MUTATION, + variables: { + input: { + organizationId: '123', + name: 'Category', + description: 'Test Description', + }, + }, + }, + error: new Error('Mock Graphql Error'), + }, +]; diff --git a/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategoryMocks.ts b/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategoryMocks.ts new file mode 100644 index 0000000000..434b0dcad2 --- /dev/null +++ b/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategoryMocks.ts @@ -0,0 +1,47 @@ +import { CREATE_AGENDA_ITEM_CATEGORY_MUTATION } from 'GraphQl/Mutations/AgendaCategoryMutations'; + +import { AGENDA_ITEM_CATEGORY_LIST } from 'GraphQl/Queries/AgendaCategoryQueries'; + +export const MOCKS = [ + { + request: { + query: AGENDA_ITEM_CATEGORY_LIST, + variables: { organizationId: '123' }, + }, + result: { + data: { + agendaItemCategoriesByOrganization: [ + { + _id: 'agendaItemCategory1', + name: 'Category', + description: 'Test Description', + createdBy: { + _id: 'user1', + firstName: 'Harve', + lastName: 'Lance', + }, + }, + ], + }, + }, + }, + { + request: { + query: CREATE_AGENDA_ITEM_CATEGORY_MUTATION, + variables: { + input: { + organizationId: '123', + name: 'Category', + description: 'Test Description', + }, + }, + }, + result: { + data: { + createAgendaCategory: { + _id: 'agendaItemCategory1', + }, + }, + }, + }, +]; diff --git a/src/screens/OrganizationDashboard/OrganizationDashboard.module.css b/src/screens/OrganizationDashboard/OrganizationDashboard.module.css new file mode 100644 index 0000000000..f9423de686 --- /dev/null +++ b/src/screens/OrganizationDashboard/OrganizationDashboard.module.css @@ -0,0 +1,29 @@ +.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.test.tsx b/src/screens/OrganizationDashboard/OrganizationDashboard.test.tsx new file mode 100644 index 0000000000..e377826a73 --- /dev/null +++ b/src/screens/OrganizationDashboard/OrganizationDashboard.test.tsx @@ -0,0 +1,202 @@ +import { MockedProvider } from '@apollo/react-testing'; +import { act, 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 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 new file mode 100644 index 0000000000..5c32d292a3 --- /dev/null +++ b/src/screens/OrganizationDashboard/OrganizationDashboard.tsx @@ -0,0 +1,351 @@ +import { useQuery } from '@apollo/client'; +import React, { useEffect, useState } from 'react'; +import { Button, Card } from 'react-bootstrap'; +import Col from 'react-bootstrap/Col'; +import Row from 'react-bootstrap/Row'; +import { useTranslation } from 'react-i18next'; + +import type { ApolloError } from '@apollo/client'; +import { + ORGANIZATIONS_LIST, + ORGANIZATION_EVENT_CONNECTION_LIST, + ORGANIZATION_POST_LIST, +} from 'GraphQl/Queries/Queries'; +import { ReactComponent as AdminsIcon } from 'assets/svgs/admin.svg'; +import { ReactComponent as BlockedUsersIcon } from 'assets/svgs/blockedUser.svg'; +import { ReactComponent as EventsIcon } from 'assets/svgs/events.svg'; +import { ReactComponent as PostsIcon } from 'assets/svgs/post.svg'; +import { ReactComponent as UsersIcon } from 'assets/svgs/users.svg'; +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 { toast } from 'react-toastify'; +import type { + InterfaceQueryOrganizationEventListItem, + InterfaceQueryOrganizationPostListItem, + InterfaceQueryOrganizationsListObject, +} from 'utils/interfaces'; +import styles from './OrganizationDashboard.module.css'; + +function organizationDashboard(): JSX.Element { + const { t } = useTranslation('translation', { keyPrefix: 'dashboard' }); + const { t: tCommon } = useTranslation('common'); + 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 requestLink = '/requests'; + + const navigate = useNavigate(); + const [upcomingEvents, setUpcomingEvents] = useState< + InterfaceQueryOrganizationEventListItem[] + >([]); + + const { + data, + loading: loadingOrgData, + error: errorOrg, + }: { + data?: { + organizations: InterfaceQueryOrganizationsListObject[]; + }; + loading: boolean; + error?: ApolloError; + } = useQuery(ORGANIZATIONS_LIST, { + variables: { id: currentUrl }, + }); + + const { + data: postData, + loading: loadingPost, + error: errorPost, + }: { + data?: { + organizations: InterfaceQueryOrganizationPostListItem[]; + }; + loading: boolean; + error?: ApolloError; + } = useQuery(ORGANIZATION_POST_LIST, { + variables: { id: currentUrl, first: 10 }, + }); + + const { + data: eventData, + loading: loadingEvent, + error: errorEvent, + } = useQuery(ORGANIZATION_EVENT_CONNECTION_LIST, { + variables: { + organization_id: currentUrl, + }, + }); + + // UseEffect to update upcomingEvents array + useEffect(() => { + if (eventData && eventData?.eventsByOrganizationConnection.length > 0) { + const tempUpcomingEvents: InterfaceQueryOrganizationEventListItem[] = []; + eventData?.eventsByOrganizationConnection.map( + (event: InterfaceQueryOrganizationEventListItem) => { + const startDate = new Date(event.startDate); + const now = new Date(); + if (startDate > now) { + tempUpcomingEvents.push(event); + } + }, + ); + setUpcomingEvents(tempUpcomingEvents); + } + }, [eventData?.eventsByOrganizationConnection]); + + useEffect(() => { + if (errorOrg || errorPost || errorEvent) { + console.log('error', errorPost?.message); + navigate('/orglist'); + } + }, [errorOrg, errorPost, errorEvent]); + + return ( + <> + + + {loadingOrgData ? ( + + {[...Array(6)].map((_, index) => { + return ( + + + + ); + })} + + ) : ( + + { + navigate(peopleLink); + }} + > + } + /> + + { + navigate(peopleLink); + }} + > + } + /> + + { + navigate(postsLink); + }} + > + } + /> + + { + navigate(eventsLink); + }} + > + } + /> + + { + navigate(blockUserLink); + }} + > + } + /> + + { + navigate(requestLink); + }} + > + } + /> + + + )} + + + +
    +
    {t('upcomingEvents')}
    + +
    + + {loadingEvent ? ( + [...Array(4)].map((_, index) => { + return ; + }) + ) : upcomingEvents.length == 0 ? ( +
    +
    {t('noUpcomingEvents')}
    +
    + ) : ( + upcomingEvents.map( + (event: InterfaceQueryOrganizationEventListItem) => { + return ( + + ); + }, + ) + )} +
    +
    + + + +
    +
    {t('latestPosts')}
    + +
    + + {loadingPost ? ( + [...Array(4)].map((_, index) => { + return ; + }) + ) : postData?.organizations[0].posts.totalCount == 0 ? ( + /* eslint-disable */ +
    +
    {t('noPostsPresent')}
    +
    + ) : ( + /* eslint-enable */ + postData?.organizations[0].posts.edges + .slice(0, 5) + .map((edge) => { + const post = edge.node; + return ( + + ); + }) + )} +
    +
    + +
    + + + +
    +
    {t('membershipRequests')}
    + +
    + + {loadingOrgData ? ( + [...Array(4)].map((_, index) => { + return ; + }) + ) : data?.organizations[0].membershipRequests.length == 0 ? ( +
    +
    {t('noMembershipRequests')}
    +
    + ) : ( + data?.organizations[0]?.membershipRequests + .slice(0, 8) + .map((request) => { + return ( + + ); + }) + )} +
    +
    + +
    + + ); +} + +export default organizationDashboard; diff --git a/src/screens/OrganizationDashboard/OrganizationDashboardMocks.ts b/src/screens/OrganizationDashboard/OrganizationDashboardMocks.ts new file mode 100644 index 0000000000..26e5441f92 --- /dev/null +++ b/src/screens/OrganizationDashboard/OrganizationDashboardMocks.ts @@ -0,0 +1,354 @@ +import { + ORGANIZATIONS_LIST, + ORGANIZATION_EVENT_CONNECTION_LIST, + ORGANIZATION_POST_LIST, +} from 'GraphQl/Queries/Queries'; + +export const MOCKS = [ + { + request: { + query: ORGANIZATIONS_LIST, + }, + result: { + data: { + organizations: [ + { + _id: 123, + image: '', + name: 'Dummy Organization', + description: 'This is a Dummy Organization', + address: { + city: 'Delhi', + countryCode: 'IN', + dependentLocality: 'Some Dependent Locality', + line1: '123 Random Street', + line2: 'Apartment 456', + postalCode: '110001', + sortingCode: 'ABC-123', + state: 'Delhi', + }, + userRegistrationRequired: true, + visibleInSearch: false, + creator: { + firstName: '', + lastName: '', + email: '', + }, + members: [ + { + _id: '123', + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@gmail.com', + }, + ], + admins: [ + { + _id: '123', + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@gmail.com', + createdAt: '12-03-2024', + }, + ], + membershipRequests: [ + { + _id: '456', + user: { + firstName: 'Jane', + lastName: 'Doe', + email: 'janedoe@gmail.com', + }, + }, + ], + blockedUsers: [ + { + _id: '789', + firstName: 'Steve', + lastName: 'Smith', + email: 'stevesmith@gmail.com', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: ORGANIZATION_POST_LIST, + variables: { first: 10 }, + }, + result: { + data: { + organizations: [ + { + posts: { + edges: [ + { + node: { + _id: '6411e53835d7ba2344a78e21', + title: 'postone', + text: 'This is the first post', + imageUrl: null, + videoUrl: null, + createdAt: '2023-08-24T09:26:56.524+00:00', + creator: { + _id: '640d98d9eb6a743d75341067', + firstName: 'Aditya', + lastName: 'Shelke', + email: 'adidacreator1@gmail.com', + }, + likeCount: 0, + commentCount: 0, + comments: [], + pinned: true, + likedBy: [], + }, + cursor: '6411e53835d7ba2344a78e21', + }, + { + node: { + _id: '6411e54835d7ba2344a78e29', + title: 'posttwo', + text: 'Tis is the post two', + imageUrl: null, + videoUrl: null, + createdAt: '2023-08-24T09:26:56.524+00:00', + creator: { + _id: '640d98d9eb6a743d75341067', + firstName: 'Aditya', + lastName: 'Shelke', + email: 'adidacreator1@gmail.com', + }, + likeCount: 0, + commentCount: 0, + pinned: false, + likedBy: [], + comments: [], + }, + cursor: '6411e54835d7ba2344a78e29', + }, + { + node: { + _id: '6411e54835d7ba2344a78e30', + title: 'posttwo', + text: 'Tis is the post two', + imageUrl: null, + videoUrl: null, + createdAt: '2023-08-24T09:26:56.524+00:00', + creator: { + _id: '640d98d9eb6a743d75341067', + firstName: 'Aditya', + lastName: 'Shelke', + email: 'adidacreator1@gmail.com', + }, + likeCount: 0, + commentCount: 0, + pinned: true, + likedBy: [], + comments: [], + }, + cursor: '6411e54835d7ba2344a78e30', + }, + { + node: { + _id: '6411e54835d7ba2344a78e31', + title: 'posttwo', + text: 'Tis is the post two', + imageUrl: null, + videoUrl: null, + createdAt: '2023-08-24T09:26:56.524+00:00', + creator: { + _id: '640d98d9eb6a743d75341067', + firstName: 'Aditya', + lastName: 'Shelke', + email: 'adidacreator1@gmail.com', + }, + likeCount: 0, + commentCount: 0, + pinned: false, + likedBy: [], + comments: [], + }, + cursor: '6411e54835d7ba2344a78e31', + }, + ], + pageInfo: { + startCursor: '6411e53835d7ba2344a78e21', + endCursor: '6411e54835d7ba2344a78e31', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 4, + }, + }, + ], + }, + }, + }, + { + request: { + query: ORGANIZATION_EVENT_CONNECTION_LIST, + variables: { + organization_id: '123', + }, + }, + result: { + data: { + eventsByOrganizationConnection: [ + { + _id: '1', + title: 'Sample Event', + description: 'Sample Description', + startDate: '2025-10-29T00:00:00.000Z', + endDate: '2023-10-29T23:59:59.000Z', + location: 'Sample Location', + startTime: '08:00:00', + endTime: '17:00:00', + allDay: false, + recurring: false, + recurrenceRule: null, + isRecurringEventException: false, + isPublic: true, + isRegisterable: true, + }, + { + _id: '2', + title: 'Sample Event', + description: 'Sample Description', + startDate: '2022-10-29T00:00:00.000Z', + endDate: '2023-10-29T23:59:59.000Z', + location: 'Sample Location', + startTime: '08:00:00', + endTime: '17:00:00', + allDay: false, + recurring: false, + recurrenceRule: null, + isRecurringEventException: false, + isPublic: true, + isRegisterable: true, + }, + ], + }, + }, + }, +]; + +export const EMPTY_MOCKS = [ + { + request: { + query: ORGANIZATIONS_LIST, + }, + result: { + data: { + organizations: [ + { + _id: 123, + image: '', + name: 'Dummy Organization', + description: 'This is a Dummy Organization', + address: { + city: 'Delhi', + countryCode: 'IN', + dependentLocality: 'Some Dependent Locality', + line1: '123 Random Street', + line2: 'Apartment 456', + postalCode: '110001', + sortingCode: 'ABC-123', + state: 'Delhi', + }, + userRegistrationRequired: true, + visibleInSearch: false, + creator: { + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@gmail.com', + }, + members: [ + { + _id: '123', + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@gmail.com', + }, + ], + admins: [ + { + _id: '123', + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@gmail.com', + createdAt: '12-03-2024', + }, + ], + membershipRequests: [], + blockedUsers: [ + { + _id: '789', + firstName: 'Steve', + lastName: 'Smith', + email: 'stevesmith@gmail.com', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: ORGANIZATION_POST_LIST, + variables: { first: 10 }, + }, + result: { + data: { + organizations: [ + { + posts: { + edges: [], + pageInfo: { + startCursor: '', + endCursor: '', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 0, + }, + }, + ], + }, + }, + }, + { + request: { + query: ORGANIZATION_EVENT_CONNECTION_LIST, + }, + result: { + data: { + eventsByOrganizationConnection: [], + }, + }, + }, +]; + +export const ERROR_MOCKS = [ + { + request: { + query: ORGANIZATIONS_LIST, + }, + error: new Error('Mock Graphql ORGANIZATIONS_LIST Error'), + }, + { + request: { + query: ORGANIZATION_POST_LIST, + }, + error: new Error('Mock Graphql ORGANIZATION_POST_LIST Error'), + }, + { + request: { + query: ORGANIZATION_EVENT_CONNECTION_LIST, + }, + error: new Error('Mock Graphql ORGANIZATION_EVENT_LIST Error'), + }, +]; diff --git a/src/screens/OrganizationEvents/OrganizationEvents.module.css b/src/screens/OrganizationEvents/OrganizationEvents.module.css new file mode 100644 index 0000000000..55e86fcaba --- /dev/null +++ b/src/screens/OrganizationEvents/OrganizationEvents.module.css @@ -0,0 +1,330 @@ +.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: block; + 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; + justify-content: space-between; +} +.dispflex > input { + border: none; + box-shadow: none; + margin-top: 5px; +} +.checkboxdiv { + display: flex; + margin-bottom: 5px; +} +.checkboxdiv > div { + width: 50%; +} + +.recurrenceRuleNumberInput { + width: 70px; +} + +.recurrenceRuleDateBox { + width: 70%; +} + +.recurrenceDayButton { + width: 33px; + height: 33px; + border: 1px solid var(--bs-gray); + cursor: pointer; + transition: background-color 0.3s; + display: inline-flex; + justify-content: center; + align-items: center; + margin-right: 0.5rem; + border-radius: 50%; +} + +.recurrenceDayButton:hover { + background-color: var(--bs-gray); +} + +.recurrenceDayButton.selected { + background-color: var(--bs-primary); + border-color: var(--bs-primary); + color: var(--bs-white); +} + +.recurrenceDayButton span { + color: var(--bs-gray); + padding: 0.25rem; + text-align: center; +} + +.recurrenceDayButton:hover span { + color: var(--bs-white); +} + +.recurrenceDayButton.selected span { + color: var(--bs-white); +} + +.recurrenceRuleSubmitBtn { + margin-left: 82%; + padding: 7px 15px; +} + +@media only screen and (max-width: 600px) { + .form_wrapper { + width: 90%; + top: 45%; + } +} diff --git a/src/screens/OrganizationEvents/OrganizationEvents.test.tsx b/src/screens/OrganizationEvents/OrganizationEvents.test.tsx new file mode 100644 index 0000000000..6c0491e2b2 --- /dev/null +++ b/src/screens/OrganizationEvents/OrganizationEvents.test.tsx @@ -0,0 +1,464 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { + act, + render, + screen, + fireEvent, + waitFor, +} 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 OrganizationEvents from './OrganizationEvents'; +import { store } from 'state/store'; +import i18n from 'utils/i18nForTest'; +import userEvent from '@testing-library/user-event'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { toast } from 'react-toastify'; +import { createTheme } from '@mui/material'; +import { ThemeProvider } from 'react-bootstrap'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { MOCKS } from './OrganizationEventsMocks'; + +const theme = createTheme({ + palette: { + primary: { + main: '#31bb6b', + }, + }, +}); + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink([], true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const translations = { + ...JSON.parse( + JSON.stringify( + i18n.getDataByLanguage('en')?.translation.organizationEvents ?? {}, + ), + ), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), +}; + +jest.mock('@mui/x-date-pickers/DateTimePicker', () => { + return { + DateTimePicker: jest.requireActual( + '@mui/x-date-pickers/DesktopDateTimePicker', + ).DesktopDateTimePicker, + }; +}); + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + warning: jest.fn(), + error: jest.fn(), + }, +})); + +describe('Organisation Events Page', () => { + const formData = { + title: 'Dummy Org', + description: 'This is a dummy organization', + startDate: '03/28/2022', + endDate: '03/30/2022', + location: 'New Delhi', + startTime: '09:00 AM', + endTime: '05:00 PM', + }; + + global.alert = jest.fn(); + + test('It is necessary to query the correct mock data.', async () => { + const dataQuery1 = MOCKS[0]?.result?.data?.eventsByOrganizationConnection; + + expect(dataQuery1).toEqual([ + { + _id: 1, + title: 'Event', + description: 'Event Test', + startDate: '', + endDate: '', + location: 'New Delhi', + startTime: '02:00', + endTime: '06:00', + allDay: false, + recurring: false, + recurrenceRule: null, + isRecurringEventException: false, + isPublic: true, + isRegisterable: true, + }, + ]); + }); + test('It is necessary to query the correct mock data for organization.', async () => { + const dataQuery1 = MOCKS[1]?.result?.data?.eventsByOrganizationConnection; + + expect(dataQuery1).toEqual([ + { + _id: '1', + title: 'Dummy Org', + description: 'This is a dummy organization', + location: 'string', + startDate: '', + endDate: '', + startTime: '02:00', + endTime: '06:00', + allDay: false, + recurring: false, + recurrenceRule: null, + isRecurringEventException: false, + isPublic: true, + isRegisterable: true, + }, + ]); + }); + test('It is necessary to check correct render', async () => { + window.location.assign('/orglist'); + + const { container } = render( + + + + + + + + + + + + + , + ); + + expect(container.textContent).not.toBe('Loading data...'); + await wait(); + expect(container.textContent).toMatch('Month'); + expect(window.location).toBeAt('/orglist'); + }); + + test('No mock data', async () => { + render( + + + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createEventModalBtn')).toBeInTheDocument(); + }); + }); + + test('Testing toggling of Create event modal', async () => { + render( + + + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createEventModalBtn')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('createEventModalBtn')); + + await waitFor(() => { + expect( + screen.getByTestId('createEventModalCloseBtn'), + ).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('createEventModalCloseBtn')); + + await waitFor(() => { + expect( + screen.queryByTestId('createEventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('Testing Create event modal', async () => { + render( + + + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createEventModalBtn')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('createEventModalBtn')); + + await waitFor(() => { + expect(screen.getByPlaceholderText(/Enter Title/i)).toBeInTheDocument(); + }); + + userEvent.type(screen.getByPlaceholderText(/Enter Title/i), formData.title); + + userEvent.type( + screen.getByPlaceholderText(/Enter Description/i), + formData.description, + ); + userEvent.type(screen.getByPlaceholderText(/Location/i), formData.location); + + const endDatePicker = screen.getByLabelText('End Date'); + const startDatePicker = screen.getByLabelText('Start Date'); + + fireEvent.change(endDatePicker, { + target: { value: formData.endDate }, + }); + fireEvent.change(startDatePicker, { + target: { value: formData.startDate }, + }); + + userEvent.click(screen.getByTestId('ispublicCheck')); + userEvent.click(screen.getByTestId('registrableCheck')); + + await wait(); + + expect(screen.getByPlaceholderText(/Enter Title/i)).toHaveValue( + formData.title, + ); + expect(screen.getByPlaceholderText(/Enter Description/i)).toHaveValue( + formData.description, + ); + + expect(endDatePicker).toHaveValue(formData.endDate); + expect(startDatePicker).toHaveValue(formData.startDate); + expect(screen.getByTestId('ispublicCheck')).not.toBeChecked(); + expect(screen.getByTestId('registrableCheck')).toBeChecked(); + + userEvent.click(screen.getByTestId('createEventBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.eventCreated); + }); + + await waitFor(() => { + expect( + screen.queryByTestId('createEventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('Testing Create event with invalid inputs', async () => { + const formData = { + title: ' ', + description: ' ', + location: ' ', + startDate: '03/28/2022', + endDate: '03/30/2022', + startTime: '02:00', + endTime: '06:00', + allDay: false, + recurring: false, + isPublic: true, + isRegisterable: true, + }; + + render( + + + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createEventModalBtn')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('createEventModalBtn')); + + await waitFor(() => { + expect(screen.getByPlaceholderText(/Enter Title/i)).toBeInTheDocument(); + }); + + userEvent.type(screen.getByPlaceholderText(/Enter Title/i), formData.title); + userEvent.type( + screen.getByPlaceholderText(/Enter Description/i), + formData.description, + ); + userEvent.type(screen.getByPlaceholderText(/Location/i), formData.location); + userEvent.type(screen.getByPlaceholderText(/Location/i), formData.location); + + const endDatePicker = screen.getByLabelText('End Date'); + const startDatePicker = screen.getByLabelText('Start Date'); + + fireEvent.change(endDatePicker, { + target: { value: formData.endDate }, + }); + fireEvent.change(startDatePicker, { + target: { value: formData.startDate }, + }); + + userEvent.click(screen.getByTestId('alldayCheck')); + userEvent.click(screen.getByTestId('recurringCheck')); + userEvent.click(screen.getByTestId('ispublicCheck')); + userEvent.click(screen.getByTestId('registrableCheck')); + + await wait(); + + expect(screen.getByPlaceholderText(/Enter Title/i)).toHaveValue(' '); + expect(screen.getByPlaceholderText(/Enter Description/i)).toHaveValue(' '); + + expect(endDatePicker).toHaveValue(formData.endDate); + expect(startDatePicker).toHaveValue(formData.startDate); + expect(screen.getByTestId('alldayCheck')).not.toBeChecked(); + expect(screen.getByTestId('recurringCheck')).toBeChecked(); + expect(screen.getByTestId('ispublicCheck')).not.toBeChecked(); + 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!'); + + userEvent.click(screen.getByTestId('createEventModalCloseBtn')); + + await waitFor(() => { + expect( + screen.queryByTestId('createEventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); + + test('Testing create event if the event is not for all day', async () => { + render( + + + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createEventModalBtn')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('createEventModalBtn')); + + await waitFor(() => { + expect(screen.getByPlaceholderText(/Enter Title/i)).toBeInTheDocument(); + }); + + userEvent.type(screen.getByPlaceholderText(/Enter Title/i), formData.title); + + userEvent.type( + screen.getByPlaceholderText(/Enter Description/i), + formData.description, + ); + + userEvent.type(screen.getByPlaceholderText(/Location/i), formData.location); + + const endDatePicker = screen.getByLabelText('End Date'); + const startDatePicker = screen.getByLabelText('Start Date'); + + fireEvent.change(endDatePicker, { + target: { value: formData.endDate }, + }); + fireEvent.change(startDatePicker, { + target: { value: formData.startDate }, + }); + + userEvent.click(screen.getByTestId('alldayCheck')); + + await waitFor(() => { + expect(screen.getByLabelText(translations.startTime)).toBeInTheDocument(); + }); + + const startTimePicker = screen.getByLabelText(translations.startTime); + const endTimePicker = screen.getByLabelText(translations.endTime); + + fireEvent.change(startTimePicker, { + target: { value: formData.startTime }, + }); + + fireEvent.change(endTimePicker, { + target: { value: formData.endTime }, + }); + + userEvent.click(screen.getByTestId('createEventBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.eventCreated); + }); + + await waitFor(() => { + expect( + screen.queryByTestId('createEventModalCloseBtn'), + ).not.toBeInTheDocument(); + }); + }); +}); diff --git a/src/screens/OrganizationEvents/OrganizationEvents.tsx b/src/screens/OrganizationEvents/OrganizationEvents.tsx new file mode 100644 index 0000000000..aaa6f911a6 --- /dev/null +++ b/src/screens/OrganizationEvents/OrganizationEvents.tsx @@ -0,0 +1,493 @@ +import React, { useState, useEffect } from 'react'; +import Button from 'react-bootstrap/Button'; +import Modal from 'react-bootstrap/Modal'; +import { Form, Popover } from 'react-bootstrap'; +import { useMutation, useQuery } from '@apollo/client'; +import { toast } from 'react-toastify'; +import { useTranslation } from 'react-i18next'; +import EventCalendar from 'components/EventCalendar/EventCalendar'; +import { TimePicker, DatePicker } from '@mui/x-date-pickers'; +import styles from './OrganizationEvents.module.css'; +import { + ORGANIZATION_EVENT_CONNECTION_LIST, + ORGANIZATIONS_LIST, +} from 'GraphQl/Queries/Queries'; +import { CREATE_EVENT_MUTATION } from 'GraphQl/Mutations/mutations'; +import type { Dayjs } from 'dayjs'; +import dayjs from 'dayjs'; +import { errorHandler } from 'utils/errorHandler'; +import Loader from 'components/Loader/Loader'; +import useLocalStorage from 'utils/useLocalstorage'; +import { useParams, useNavigate } from 'react-router-dom'; +import EventHeader from 'components/EventCalendar/EventHeader'; +import { + Frequency, + Days, + getRecurrenceRuleText, + getWeekDayOccurenceInMonth, +} from 'utils/recurrenceUtils'; +import type { InterfaceRecurrenceRuleState } from 'utils/recurrenceUtils'; +import RecurrenceOptions from 'components/RecurrenceOptions/RecurrenceOptions'; + +const timeToDayJs = (time: string): Dayjs => { + const dateTimeString = dayjs().format('YYYY-MM-DD') + ' ' + time; + return dayjs(dateTimeString, { format: 'YYYY-MM-DD HH:mm:ss' }); +}; + +export enum ViewType { + DAY = 'Day', + MONTH = 'Month View', + YEAR = 'Year View', +} + +function organizationEvents(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'organizationEvents', + }); + const { t: tCommon } = useTranslation('common'); + + const { getItem } = useLocalStorage(); + + document.title = t('title'); + const [createEventmodalisOpen, setCreateEventmodalisOpen] = useState(false); + const [startDate, setStartDate] = React.useState(new Date()); + const [endDate, setEndDate] = React.useState(new Date()); + const [viewType, setViewType] = useState(ViewType.MONTH); + const [alldaychecked, setAllDayChecked] = React.useState(true); + const [recurringchecked, setRecurringChecked] = React.useState(false); + + const [publicchecked, setPublicChecked] = React.useState(true); + const [registrablechecked, setRegistrableChecked] = React.useState(false); + + const [recurrenceRuleState, setRecurrenceRuleState] = + useState({ + recurrenceStartDate: startDate, + recurrenceEndDate: null, + frequency: Frequency.WEEKLY, + weekDays: [Days[startDate.getDay()]], + interval: 1, + count: undefined, + weekDayOccurenceInMonth: undefined, + }); + + const [formState, setFormState] = useState({ + title: '', + eventdescrip: '', + date: '', + location: '', + startTime: '08:00:00', + endTime: '18:00:00', + }); + const { orgId: currentUrl } = useParams(); + const navigate = useNavigate(); + + const showInviteModal = (): void => { + setCreateEventmodalisOpen(true); + }; + const hideCreateEventModal = (): void => { + setCreateEventmodalisOpen(false); + }; + const handleChangeView = (item: string | null): void => { + /*istanbul ignore next*/ + if (item) { + setViewType(item as ViewType); + } + }; + + const { + data, + loading, + error: eventDataError, + refetch: refetchEvents, + } = useQuery(ORGANIZATION_EVENT_CONNECTION_LIST, { + variables: { + organization_id: currentUrl, + title_contains: '', + description_contains: '', + location_contains: '', + }, + }); + + const { data: orgData } = useQuery(ORGANIZATIONS_LIST, { + variables: { id: currentUrl }, + }); + + const userId = getItem('id') as string; + const superAdmin = getItem('SuperAdmin'); + const adminFor = getItem('AdminFor'); + const userRole = superAdmin + ? 'SUPERADMIN' + : adminFor?.length > 0 + ? 'ADMIN' + : 'USER'; + + const [create, { loading: loading2 }] = useMutation(CREATE_EVENT_MUTATION); + + const { + recurrenceStartDate, + recurrenceEndDate, + frequency, + weekDays, + interval, + count, + weekDayOccurenceInMonth, + } = recurrenceRuleState; + + const recurrenceRuleText = getRecurrenceRuleText(recurrenceRuleState); + + const createEvent = async ( + e: React.ChangeEvent, + ): Promise => { + e.preventDefault(); + if ( + formState.title.trim().length > 0 && + formState.eventdescrip.trim().length > 0 && + formState.location.trim().length > 0 + ) { + try { + const { data: createEventData } = await create({ + variables: { + title: formState.title, + description: formState.eventdescrip, + isPublic: publicchecked, + recurring: recurringchecked, + isRegisterable: registrablechecked, + organizationId: currentUrl, + startDate: dayjs(startDate).format('YYYY-MM-DD'), + endDate: dayjs(endDate).format('YYYY-MM-DD'), + allDay: alldaychecked, + location: formState.location, + startTime: !alldaychecked ? formState.startTime + 'Z' : undefined, + endTime: !alldaychecked ? formState.endTime + 'Z' : undefined, + recurrenceStartDate: recurringchecked + ? dayjs(recurrenceStartDate).format('YYYY-MM-DD') + : undefined, + recurrenceEndDate: recurringchecked + ? recurrenceEndDate + ? dayjs(recurrenceEndDate).format('YYYY-MM-DD') + : null + : undefined, + frequency: recurringchecked ? frequency : undefined, + weekDays: + recurringchecked && + (frequency === Frequency.WEEKLY || + (frequency === Frequency.MONTHLY && weekDayOccurenceInMonth)) + ? weekDays + : undefined, + interval: recurringchecked ? interval : undefined, + count: recurringchecked ? count : undefined, + weekDayOccurenceInMonth: recurringchecked + ? weekDayOccurenceInMonth + : undefined, + }, + }); + + if (createEventData) { + toast.success(t('eventCreated')); + refetchEvents(); + hideCreateEventModal(); + setFormState({ + title: '', + eventdescrip: '', + date: '', + location: '', + startTime: '08:00:00', + endTime: '18:00:00', + }); + setRecurringChecked(false); + setRecurrenceRuleState({ + recurrenceStartDate: new Date(), + recurrenceEndDate: null, + frequency: Frequency.WEEKLY, + weekDays: [Days[new Date().getDay()]], + interval: 1, + count: undefined, + weekDayOccurenceInMonth: undefined, + }); + setStartDate(new Date()); + setEndDate(new Date()); + } + } catch (error: unknown) { + /* istanbul ignore next */ + if (error instanceof Error) { + console.log(error.message); + errorHandler(t, error); + } + } + } + if (formState.title.trim().length === 0) { + toast.warning('Title can not be blank!'); + } + if (formState.eventdescrip.trim().length === 0) { + toast.warning('Description can not be blank!'); + } + if (formState.location.trim().length === 0) { + toast.warning('Location can not be blank!'); + } + }; + + useEffect(() => { + if (eventDataError) { + navigate('/orglist'); + } + }, [eventDataError]); + + if (loading || loading2) { + return ; + } + + const popover = ( + + {recurrenceRuleText} + + ); + + return ( + <> +
    +
    + +
    +
    + + + {/* Create Event Modal */} + + +

    {t('eventDetails')}

    + +
    + +
    + + { + setFormState({ + ...formState, + title: e.target.value, + }); + }} + /> + + { + setFormState({ + ...formState, + eventdescrip: e.target.value, + }); + }} + /> + + { + setFormState({ + ...formState, + location: e.target.value, + }); + }} + /> +
    +
    + { + if (date) { + setStartDate(date?.toDate()); + setEndDate( + endDate < date?.toDate() ? date?.toDate() : endDate, + ); + setRecurrenceRuleState({ + ...recurrenceRuleState, + recurrenceStartDate: date?.toDate(), + weekDays: [Days[date?.toDate().getDay()]], + weekDayOccurenceInMonth: weekDayOccurenceInMonth + ? getWeekDayOccurenceInMonth(date?.toDate()) + : undefined, + }); + } + }} + /> +
    +
    + { + if (date) { + setEndDate(date?.toDate()); + } + }} + minDate={dayjs(startDate)} + /> +
    +
    + {!alldaychecked && ( +
    +
    + { + if (time) { + setFormState({ + ...formState, + startTime: time?.format('HH:mm:ss'), + endTime: + /*istanbul ignore next*/ + timeToDayJs(formState.endTime) < time + ? /* istanbul ignore next */ time?.format( + 'HH:mm:ss', + ) + : formState.endTime, + }); + } + }} + disabled={alldaychecked} + /> +
    +
    + { + if (time) { + setFormState({ + ...formState, + endTime: time?.format('HH:mm:ss'), + }); + } + }} + minTime={timeToDayJs(formState.startTime)} + disabled={alldaychecked} + /> +
    +
    + )} +
    +
    + + setAllDayChecked(!alldaychecked)} + /> +
    +
    + + setPublicChecked(!publicchecked)} + /> +
    +
    +
    +
    + + { + setRecurringChecked(!recurringchecked); + }} + /> +
    +
    + + + setRegistrableChecked(!registrablechecked) + } + /> +
    +
    + + {/* Recurrence Options */} + {recurringchecked && ( + + )} + + + +
    +
    + + ); +} + +export default organizationEvents; diff --git a/src/screens/OrganizationEvents/OrganizationEventsMocks.ts b/src/screens/OrganizationEvents/OrganizationEventsMocks.ts new file mode 100644 index 0000000000..3ff2d73d5a --- /dev/null +++ b/src/screens/OrganizationEvents/OrganizationEventsMocks.ts @@ -0,0 +1,241 @@ +import { CREATE_EVENT_MUTATION } from 'GraphQl/Mutations/mutations'; +import { ORGANIZATION_EVENT_CONNECTION_LIST } from 'GraphQl/Queries/Queries'; + +export const MOCKS = [ + { + request: { + query: ORGANIZATION_EVENT_CONNECTION_LIST, + variables: { + organization_id: undefined, + title_contains: '', + description_contains: '', + location_contains: '', + }, + }, + result: { + data: { + eventsByOrganizationConnection: [ + { + _id: 1, + title: 'Event', + description: 'Event Test', + startDate: '', + endDate: '', + location: 'New Delhi', + startTime: '02:00', + endTime: '06:00', + allDay: false, + recurring: false, + recurrenceRule: null, + isRecurringEventException: false, + isPublic: true, + isRegisterable: true, + }, + ], + }, + }, + }, + { + request: { + query: ORGANIZATION_EVENT_CONNECTION_LIST, + variables: { + title_contains: '', + description_contains: '', + organization_id: undefined, + location_contains: '', + }, + }, + result: { + data: { + eventsByOrganizationConnection: [ + { + _id: '1', + title: 'Dummy Org', + description: 'This is a dummy organization', + location: 'string', + startDate: '', + endDate: '', + startTime: '02:00', + endTime: '06:00', + allDay: false, + recurring: false, + recurrenceRule: null, + isRecurringEventException: false, + isPublic: true, + isRegisterable: true, + }, + ], + }, + }, + }, + { + request: { + query: CREATE_EVENT_MUTATION, + variables: { + title: 'Dummy Org', + location: 'New Delhi', + description: 'This is a dummy organization', + isPublic: false, + recurring: false, + isRegisterable: true, + organizationId: undefined, + startDate: '2022-03-28', + endDate: '2022-03-30', + allDay: true, + }, + }, + result: { + data: { + createEvent: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: CREATE_EVENT_MUTATION, + variables: { + title: 'Dummy Org', + location: 'New Delhi', + description: 'This is a dummy organization', + isPublic: true, + recurring: false, + isRegisterable: false, + organizationId: undefined, + startDate: '2022-03-28', + endDate: '2022-03-30', + allDay: false, + startTime: '09:00:00Z', + endTime: '17:00:00Z', + }, + }, + result: { + data: { + createEvent: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: CREATE_EVENT_MUTATION, + variables: { + title: 'Dummy Org', + location: 'New Delhi', + description: 'This is a dummy organization', + isPublic: true, + recurring: true, + isRegisterable: false, + organizationId: undefined, + startDate: '2022-03-28', + endDate: '2022-03-30', + allDay: false, + startTime: '09:00:00Z', + endTime: '17:00:00Z', + recurrenceStartDate: '2022-03-28', + recurrenceEndDate: null, + frequency: 'DAILY', + interval: 1, + }, + }, + result: { + data: { + createEvent: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: CREATE_EVENT_MUTATION, + variables: { + title: 'Dummy Org', + location: 'New Delhi', + description: 'This is a dummy organization', + isPublic: true, + recurring: true, + isRegisterable: false, + organizationId: undefined, + startDate: '2022-03-28', + endDate: '2022-03-30', + allDay: false, + startTime: '09:00:00Z', + endTime: '17:00:00Z', + recurrenceStartDate: '2022-03-28', + recurrenceEndDate: null, + frequency: 'WEEKLY', + interval: 1, + weekDays: ['MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY'], + }, + }, + result: { + data: { + createEvent: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: CREATE_EVENT_MUTATION, + variables: { + title: 'Dummy Org', + description: 'This is a dummy organization', + location: 'New Delhi', + organizationId: undefined, + isPublic: true, + recurring: true, + isRegisterable: false, + startDate: '2022-03-28', + endDate: '2022-03-30', + allDay: true, + recurrenceStartDate: '2022-03-28', + recurrenceEndDate: '2023-04-15', + frequency: 'MONTHLY', + weekDays: ['MONDAY'], + interval: 2, + weekDayOccurenceInMonth: 4, + }, + }, + result: { + data: { + createEvent: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: CREATE_EVENT_MUTATION, + variables: { + title: 'Dummy Org', + location: 'New Delhi', + description: 'This is a dummy organization', + isPublic: true, + recurring: true, + isRegisterable: false, + organizationId: undefined, + startDate: '2022-03-28', + endDate: '2022-03-30', + allDay: true, + recurrenceStartDate: '2022-03-28', + recurrenceEndDate: null, + frequency: 'DAILY', + interval: 1, + count: 100, + }, + }, + result: { + data: { + createEvent: { + _id: '1', + }, + }, + }, + }, +]; diff --git a/src/screens/OrganizationFundCampaign/CampaignDeleteModal.test.tsx b/src/screens/OrganizationFundCampaign/CampaignDeleteModal.test.tsx new file mode 100644 index 0000000000..7baf9bd933 --- /dev/null +++ b/src/screens/OrganizationFundCampaign/CampaignDeleteModal.test.tsx @@ -0,0 +1,95 @@ +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 i18nForTest from '../../utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { toast } from 'react-toastify'; +import { MOCKS, MOCK_ERROR } from './OrganizationFundCampaignMocks'; +import CampaignDeleteModal, { + type InterfaceDeleteCampaignModal, +} from './CampaignDeleteModal'; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +const link1 = new StaticMockLink(MOCKS); +const link2 = new StaticMockLink(MOCK_ERROR); +const translations = JSON.parse( + JSON.stringify(i18nForTest.getDataByLanguage('en')?.translation.fundCampaign), +); + +const campaignProps: InterfaceDeleteCampaignModal = { + isOpen: true, + hide: jest.fn(), + campaign: { + _id: 'campaignId1', + name: 'Campaign 1', + fundingGoal: 100, + startDate: new Date('2021-01-01'), + endDate: new Date('2024-01-01'), + currency: 'USD', + createdAt: '2021-01-01', + }, + refetchCampaign: jest.fn(), +}; +const renderFundDeleteModal = ( + link: ApolloLink, + props: InterfaceDeleteCampaignModal, +): RenderResult => { + return render( + + + + + + + + + + + , + ); +}; + +describe('CampaignDeleteModal', () => { + it('should render CampaignDeleteModal', () => { + renderFundDeleteModal(link1, campaignProps); + expect(screen.getByTestId('deleteCampaignCloseBtn')).toBeInTheDocument(); + }); + + it('should successfully Delete Campaign', async () => { + renderFundDeleteModal(link1, campaignProps); + expect(screen.getByTestId('deleteCampaignCloseBtn')).toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('deleteyesbtn')); + + await waitFor(() => { + expect(campaignProps.refetchCampaign).toHaveBeenCalled(); + expect(campaignProps.hide).toHaveBeenCalled(); + expect(toast.success).toHaveBeenCalledWith(translations.deletedCampaign); + }); + }); + + it('should fail to Delete Campaign', async () => { + renderFundDeleteModal(link2, campaignProps); + expect(screen.getByTestId('deleteCampaignCloseBtn')).toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('deleteyesbtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith('Mock graphql error'); + }); + }); +}); diff --git a/src/screens/OrganizationFundCampaign/CampaignDeleteModal.tsx b/src/screens/OrganizationFundCampaign/CampaignDeleteModal.tsx new file mode 100644 index 0000000000..840c4869bb --- /dev/null +++ b/src/screens/OrganizationFundCampaign/CampaignDeleteModal.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import { Button, Modal } from 'react-bootstrap'; +import styles from './OrganizationFundCampaign.module.css'; +import { useMutation } from '@apollo/client'; +import { DELETE_CAMPAIGN_MUTATION } from 'GraphQl/Mutations/CampaignMutation'; +import type { InterfaceCampaignInfo } from 'utils/interfaces'; +import { toast } from 'react-toastify'; +import { useTranslation } from 'react-i18next'; + +export interface InterfaceDeleteCampaignModal { + isOpen: boolean; + hide: () => void; + campaign: InterfaceCampaignInfo | null; + refetchCampaign: () => void; +} +const CampaignDeleteModal: React.FC = ({ + isOpen, + hide, + campaign, + refetchCampaign, +}) => { + const { t } = useTranslation('translation', { + keyPrefix: 'fundCampaign', + }); + const { t: tCommon } = useTranslation('common'); + + const [deleteCampaign] = useMutation(DELETE_CAMPAIGN_MUTATION); + + const deleteCampaignHandler = async (): Promise => { + try { + await deleteCampaign({ + variables: { + id: campaign?._id, + }, + }); + toast.success(t('deletedCampaign')); + refetchCampaign(); + hide(); + } catch (error: unknown) { + toast.error((error as Error).message); + } + }; + return ( + <> + + +

    {t('deleteCampaign')}

    + +
    + +

    {t('deleteCampaignMsg')}

    +
    + + + + +
    + + ); +}; +export default CampaignDeleteModal; diff --git a/src/screens/OrganizationFundCampaign/CampaignModal.test.tsx b/src/screens/OrganizationFundCampaign/CampaignModal.test.tsx new file mode 100644 index 0000000000..cdf631f87c --- /dev/null +++ b/src/screens/OrganizationFundCampaign/CampaignModal.test.tsx @@ -0,0 +1,266 @@ +import React from 'react'; +import type { ApolloLink } from '@apollo/client'; +import { MockedProvider } from '@apollo/react-testing'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import type { RenderResult } from '@testing-library/react'; +import { + cleanup, + fireEvent, + render, + screen, + waitFor, +} from '@testing-library/react'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { store } from 'state/store'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import i18nForTest from '../../utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { toast } from 'react-toastify'; +import { MOCKS, MOCK_ERROR } from './OrganizationFundCampaignMocks'; +import type { InterfaceCampaignModal } from './CampaignModal'; +import CampaignModal from './CampaignModal'; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +jest.mock('@mui/x-date-pickers/DateTimePicker', () => { + return { + DateTimePicker: jest.requireActual( + '@mui/x-date-pickers/DesktopDateTimePicker', + ).DesktopDateTimePicker, + }; +}); + +const link1 = new StaticMockLink(MOCKS); +const link2 = new StaticMockLink(MOCK_ERROR); +const translations = JSON.parse( + JSON.stringify(i18nForTest.getDataByLanguage('en')?.translation.fundCampaign), +); + +const campaignProps: InterfaceCampaignModal[] = [ + { + isOpen: true, + hide: jest.fn(), + fundId: 'fundId', + campaign: { + _id: 'campaignId1', + name: 'Campaign 1', + fundingGoal: 100, + startDate: new Date('2021-01-01'), + endDate: new Date('2024-01-01'), + currency: 'USD', + createdAt: '2021-01-01', + }, + refetchCampaign: jest.fn(), + mode: 'create', + }, + { + isOpen: true, + hide: jest.fn(), + fundId: 'fundId', + campaign: { + _id: 'campaignId1', + name: 'Campaign 1', + fundingGoal: 100, + startDate: new Date('2021-01-01'), + endDate: new Date('2024-01-01'), + currency: 'USD', + createdAt: '2021-01-01', + }, + refetchCampaign: jest.fn(), + mode: 'edit', + }, +]; +const renderCampaignModal = ( + link: ApolloLink, + props: InterfaceCampaignModal, +): RenderResult => { + return render( + + + + + + + + + + + , + ); +}; + +describe('CampaignModal', () => { + afterEach(() => { + jest.clearAllMocks(); + cleanup(); + }); + + it('should populate form fields with correct values in edit mode', async () => { + renderCampaignModal(link1, campaignProps[1]); + await waitFor(() => + expect(screen.getAllByText(translations.updateCampaign)).toHaveLength(2), + ); + + expect(screen.getByLabelText(translations.campaignName)).toHaveValue( + 'Campaign 1', + ); + expect(screen.getByLabelText('Start Date')).toHaveValue('01/01/2021'); + expect(screen.getByLabelText('End Date')).toHaveValue('01/01/2024'); + expect(screen.getByLabelText(translations.currency)).toHaveTextContent( + 'USD ($)', + ); + expect(screen.getByLabelText(translations.fundingGoal)).toHaveValue('100'); + }); + + it('should update fundingGoal when input value changes', async () => { + renderCampaignModal(link1, campaignProps[1]); + const goalInput = screen.getByLabelText(translations.fundingGoal); + expect(goalInput).toHaveValue('100'); + fireEvent.change(goalInput, { target: { value: '200' } }); + expect(goalInput).toHaveValue('200'); + }); + + it('should not update fundingGoal when input value is less than or equal to 0', async () => { + renderCampaignModal(link1, campaignProps[1]); + const goalInput = screen.getByLabelText(translations.fundingGoal); + expect(goalInput).toHaveValue('100'); + fireEvent.change(goalInput, { target: { value: '-10' } }); + expect(goalInput).toHaveValue('100'); + }); + + it('should update Start Date when a new date is selected', async () => { + renderCampaignModal(link1, campaignProps[1]); + const startDateInput = screen.getByLabelText('Start Date'); + fireEvent.change(startDateInput, { target: { value: '02/01/2024' } }); + expect(startDateInput).toHaveValue('02/01/2024'); + }); + + it('Start Date onChange when its null', async () => { + renderCampaignModal(link1, campaignProps[1]); + const startDateInput = screen.getByLabelText('Start Date'); + expect(startDateInput).toHaveValue('01/01/2021'); + fireEvent.change(startDateInput, { target: { value: null } }); + expect(startDateInput).toHaveValue(''); + }); + + it('should update End Date when a new date is selected', async () => { + renderCampaignModal(link1, campaignProps[1]); + const endDateInput = screen.getByLabelText('End Date'); + fireEvent.change(endDateInput, { target: { value: '02/01/2024' } }); + expect(endDateInput).toHaveValue('02/01/2024'); + }); + + it('End Date onChange when its null', async () => { + renderCampaignModal(link1, campaignProps[1]); + const endDateInput = screen.getByLabelText('End Date'); + fireEvent.change(endDateInput, { target: { value: null } }); + expect(endDateInput).toHaveValue(''); + }); + + it('should create campaign', async () => { + renderCampaignModal(link1, campaignProps[0]); + + const campaignName = screen.getByLabelText(translations.campaignName); + fireEvent.change(campaignName, { target: { value: 'Campaign 2' } }); + + const startDate = screen.getByLabelText('Start Date'); + fireEvent.change(startDate, { target: { value: '02/01/2024' } }); + + const endDate = screen.getByLabelText('End Date'); + fireEvent.change(endDate, { target: { value: '02/02/2024' } }); + + const fundingGoal = screen.getByLabelText(translations.fundingGoal); + fireEvent.change(fundingGoal, { target: { value: '200' } }); + + const submitBtn = screen.getByTestId('submitCampaignBtn'); + expect(submitBtn).toBeInTheDocument(); + fireEvent.click(submitBtn); + + await waitFor(() => { + expect(toast.success).toHaveBeenCalledWith(translations.createdCampaign); + expect(campaignProps[0].refetchCampaign).toHaveBeenCalled(); + expect(campaignProps[0].hide).toHaveBeenCalled(); + }); + }); + + it('should update campaign', async () => { + renderCampaignModal(link1, campaignProps[1]); + + const campaignName = screen.getByLabelText(translations.campaignName); + fireEvent.change(campaignName, { target: { value: 'Campaign 4' } }); + + const startDate = screen.getByLabelText('Start Date'); + fireEvent.change(startDate, { target: { value: '02/01/2023' } }); + + const endDate = screen.getByLabelText('End Date'); + fireEvent.change(endDate, { target: { value: '02/02/2023' } }); + + const fundingGoal = screen.getByLabelText(translations.fundingGoal); + fireEvent.change(fundingGoal, { target: { value: '400' } }); + + const submitBtn = screen.getByTestId('submitCampaignBtn'); + expect(submitBtn).toBeInTheDocument(); + + fireEvent.click(submitBtn); + await waitFor(() => { + expect(toast.success).toHaveBeenCalledWith(translations.updatedCampaign); + expect(campaignProps[1].refetchCampaign).toHaveBeenCalled(); + expect(campaignProps[1].hide).toHaveBeenCalled(); + }); + }); + + it('Error: should create campaign', async () => { + renderCampaignModal(link2, campaignProps[0]); + + const campaignName = screen.getByLabelText(translations.campaignName); + fireEvent.change(campaignName, { target: { value: 'Campaign 2' } }); + + const startDate = screen.getByLabelText('Start Date'); + fireEvent.change(startDate, { target: { value: '02/01/2024' } }); + + const endDate = screen.getByLabelText('End Date'); + fireEvent.change(endDate, { target: { value: '02/02/2024' } }); + + const fundingGoal = screen.getByLabelText(translations.fundingGoal); + fireEvent.change(fundingGoal, { target: { value: '200' } }); + + const submitBtn = screen.getByTestId('submitCampaignBtn'); + expect(submitBtn).toBeInTheDocument(); + fireEvent.click(submitBtn); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith('Mock graphql error'); + }); + }); + + it('Error: should update campaign', async () => { + renderCampaignModal(link2, campaignProps[1]); + + const campaignName = screen.getByLabelText(translations.campaignName); + fireEvent.change(campaignName, { target: { value: 'Campaign 4' } }); + + const startDate = screen.getByLabelText('Start Date'); + fireEvent.change(startDate, { target: { value: '02/01/2023' } }); + + const endDate = screen.getByLabelText('End Date'); + fireEvent.change(endDate, { target: { value: '02/02/2023' } }); + + const fundingGoal = screen.getByLabelText(translations.fundingGoal); + fireEvent.change(fundingGoal, { target: { value: '400' } }); + + const submitBtn = screen.getByTestId('submitCampaignBtn'); + expect(submitBtn).toBeInTheDocument(); + + fireEvent.click(submitBtn); + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith('Mock graphql error'); + }); + }); +}); diff --git a/src/screens/OrganizationFundCampaign/CampaignModal.tsx b/src/screens/OrganizationFundCampaign/CampaignModal.tsx new file mode 100644 index 0000000000..dfe0738c07 --- /dev/null +++ b/src/screens/OrganizationFundCampaign/CampaignModal.tsx @@ -0,0 +1,291 @@ +import { DatePicker } from '@mui/x-date-pickers'; +import type { Dayjs } from 'dayjs'; +import dayjs from 'dayjs'; +import type { ChangeEvent } from 'react'; +import React, { useEffect, useState } from 'react'; +import { Button, Col, Form, Modal } from 'react-bootstrap'; +import { currencyOptions, currencySymbols } from 'utils/currency'; +import styles from './OrganizationFundCampaign.module.css'; +import { useTranslation } from 'react-i18next'; +import { useMutation } from '@apollo/client'; +import { + CREATE_CAMPAIGN_MUTATION, + UPDATE_CAMPAIGN_MUTATION, +} from 'GraphQl/Mutations/CampaignMutation'; +import { toast } from 'react-toastify'; +import { + FormControl, + InputLabel, + MenuItem, + Select, + TextField, +} from '@mui/material'; +import type { InterfaceCampaignInfo } from 'utils/interfaces'; + +export interface InterfaceCampaignModal { + isOpen: boolean; + hide: () => void; + fundId: string; + campaign: InterfaceCampaignInfo | null; + refetchCampaign: () => void; + mode: 'create' | 'edit'; +} + +const CampaignModal: React.FC = ({ + isOpen, + hide, + fundId, + refetchCampaign, + mode, + campaign, +}) => { + const { t } = useTranslation('translation', { + keyPrefix: 'fundCampaign', + }); + const { t: tCommon } = useTranslation('common'); + + const [formState, setFormState] = useState({ + campaignName: campaign?.name ?? '', + campaignCurrency: campaign?.currency ?? 'USD', + campaignGoal: campaign?.fundingGoal ?? 0, + campaignStartDate: campaign?.startDate ?? new Date(), + campaignEndDate: campaign?.endDate ?? new Date(), + }); + + useEffect(() => { + setFormState({ + campaignCurrency: campaign?.currency ?? 'USD', + campaignEndDate: campaign?.endDate ?? new Date(), + campaignGoal: campaign?.fundingGoal ?? 0, + campaignName: campaign?.name ?? '', + campaignStartDate: campaign?.startDate ?? new Date(), + }); + }, [campaign]); + + const { + campaignName, + campaignCurrency, + campaignEndDate, + campaignGoal, + campaignStartDate, + } = formState; + + const [createCampaign] = useMutation(CREATE_CAMPAIGN_MUTATION); + const [updateCampaign] = useMutation(UPDATE_CAMPAIGN_MUTATION); + + const createCampaignHandler = async ( + e: ChangeEvent, + ): Promise => { + e.preventDefault(); + try { + await createCampaign({ + variables: { + name: formState.campaignName, + currency: formState.campaignCurrency, + fundingGoal: formState.campaignGoal, + startDate: dayjs(formState.campaignStartDate).format('YYYY-MM-DD'), + endDate: dayjs(formState.campaignEndDate).format('YYYY-MM-DD'), + fundId, + }, + }); + toast.success(t('createdCampaign')); + setFormState({ + campaignName: '', + campaignCurrency: 'USD', + campaignGoal: 0, + campaignStartDate: new Date(), + campaignEndDate: new Date(), + }); + refetchCampaign(); + hide(); + } catch (error: unknown) { + toast.error((error as Error).message); + } + }; + + /*istanbul ignore next*/ + const updateCampaignHandler = async ( + e: ChangeEvent, + ): Promise => { + e.preventDefault(); + try { + const updatedFields: { [key: string]: string | number | undefined } = {}; + if (campaign?.name !== campaignName) { + updatedFields.name = campaignName; + } + if (campaign?.currency !== campaignCurrency) { + updatedFields.currency = campaignCurrency; + } + if (campaign?.fundingGoal !== campaignGoal) { + updatedFields.fundingGoal = campaignGoal; + } + if (campaign?.startDate !== campaignStartDate) { + updatedFields.startDate = dayjs(campaignStartDate).format('YYYY-MM-DD'); + } + if (campaign?.endDate !== formState.campaignEndDate) { + updatedFields.endDate = dayjs(formState.campaignEndDate).format( + 'YYYY-MM-DD', + ); + } + await updateCampaign({ + variables: { + id: campaign?._id, + ...updatedFields, + }, + }); + setFormState({ + campaignName: '', + campaignCurrency: 'USD', + campaignGoal: 0, + campaignStartDate: new Date(), + campaignEndDate: new Date(), + }); + refetchCampaign(); + hide(); + toast.success(t('updatedCampaign')); + } catch (error: unknown) { + toast.error((error as Error).message); + } + }; + + return ( + <> + + +

    + {t(mode === 'edit' ? 'updateCampaign' : 'createCampaign')} +

    + +
    + +
    + + + + setFormState({ + ...formState, + campaignName: e.target.value, + }) + } + /> + + + + + {/* Date Calendar Component to select start date of campaign*/} + { + if (date) { + setFormState({ + ...formState, + campaignStartDate: date.toDate(), + campaignEndDate: + campaignEndDate && + (campaignEndDate < date?.toDate() + ? date.toDate() + : campaignEndDate), + }); + } + }} + minDate={dayjs(new Date())} + /> + {/* Date Calendar Component to select end Date of campaign */} + { + if (date) { + setFormState({ + ...formState, + campaignEndDate: date.toDate(), + }); + } + }} + minDate={dayjs(campaignStartDate)} + /> + + + + {/* Dropdown to select the currency for funding goal of the campaign*/} + + + {t('currency')} + + + + {/* Input field to enter funding goal for the campaign */} + + { + if (parseInt(e.target.value) > 0) { + setFormState({ + ...formState, + campaignGoal: parseInt(e.target.value), + }); + } + }} + /> + + + {/* Button to create the campaign */} + +
    +
    +
    + + ); +}; +export default CampaignModal; diff --git a/src/screens/OrganizationFundCampaign/OrganizationFundCampagins.tsx b/src/screens/OrganizationFundCampaign/OrganizationFundCampagins.tsx new file mode 100644 index 0000000000..6cc671c5b1 --- /dev/null +++ b/src/screens/OrganizationFundCampaign/OrganizationFundCampagins.tsx @@ -0,0 +1,438 @@ +import { useQuery } from '@apollo/client'; +import { Search, Sort, WarningAmberRounded } from '@mui/icons-material'; +import { Stack, Typography, Breadcrumbs, Link } from '@mui/material'; +import { + DataGrid, + type GridCellParams, + type GridColDef, +} from '@mui/x-data-grid'; +import { Button, Dropdown, Form } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; +import { Navigate, useNavigate, useParams } from 'react-router-dom'; +import React, { useCallback, useMemo, useState } from 'react'; +import dayjs from 'dayjs'; +import Loader from 'components/Loader/Loader'; +import CampaignModal from './CampaignModal'; +import CampaignDeleteModal from './CampaignDeleteModal'; +import { FUND_CAMPAIGN } from 'GraphQl/Queries/fundQueries'; +import styles from './OrganizationFundCampaign.module.css'; +import { currencySymbols } from 'utils/currency'; +import type { + InterfaceCampaignInfo, + InterfaceQueryOrganizationFundCampaigns, +} from 'utils/interfaces'; + +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', + }, +}; + +enum ModalState { + SAME = 'same', + DELETE = 'delete', +} + +const orgFundCampaign = (): JSX.Element => { + const { t } = useTranslation('translation', { + keyPrefix: 'fundCampaign', + }); + const { t: tCommon } = useTranslation('common'); + const navigate = useNavigate(); + + const { fundId, orgId } = useParams(); + + if (!fundId || !orgId) { + return ; + } + + const [campaign, setCampaign] = useState(null); + const [searchTerm, setSearchTerm] = useState(''); + const [sortBy, setSortBy] = useState(null); + + const [modalState, setModalState] = useState<{ + [key in ModalState]: boolean; + }>({ + [ModalState.SAME]: false, + [ModalState.DELETE]: false, + }); + const [campaignModalMode, setCampaignModalMode] = useState<'edit' | 'create'>( + 'create', + ); + const openModal = (modal: ModalState): void => + setModalState((prevState) => ({ ...prevState, [modal]: true })); + + const closeModal = (modal: ModalState): void => + setModalState((prevState) => ({ ...prevState, [modal]: false })); + + const handleOpenModal = useCallback( + (campaign: InterfaceCampaignInfo | null, mode: 'edit' | 'create'): void => { + setCampaign(campaign); + setCampaignModalMode(mode); + openModal(ModalState.SAME); + }, + [openModal], + ); + + const handleDeleteClick = useCallback( + (campaign: InterfaceCampaignInfo): void => { + setCampaign(campaign); + openModal(ModalState.DELETE); + }, + [openModal], + ); + + const { + data: campaignData, + loading: campaignLoading, + error: campaignError, + refetch: refetchCampaign, + }: { + data?: { + getFundById: InterfaceQueryOrganizationFundCampaigns; + }; + loading: boolean; + error?: Error | undefined; + refetch: () => void; + } = useQuery(FUND_CAMPAIGN, { + variables: { + id: fundId, + orderBy: sortBy, + where: { + name_contains: searchTerm, + }, + }, + }); + + const handleClick = (campaignId: string): void => { + navigate(`/fundCampaignPledge/${orgId}/${campaignId}`); + }; + + const campaigns = useMemo(() => { + if (campaignData?.getFundById?.campaigns) + return campaignData.getFundById.campaigns; + return []; + }, [campaignData]); + + if (campaignLoading) { + return ; + } + if (campaignError) { + return ( +
    +
    + +
    + Error occured while loading Campaigns +
    + {campaignError.message} +
    +
    +
    + ); + } + + const columns: GridColDef[] = [ + { + field: 'id', + headerName: 'Sr. No.', + flex: 1, + minWidth: 100, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return
    {params.row.id}
    ; + }, + }, + { + field: 'campaignName', + headerName: 'Campaign Name', + flex: 2, + minWidth: 150, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return ( +
    handleClick(params.row.campaign._id as string)} + > + {params.row.campaign.name} +
    + ); + }, + }, + { + field: 'startDate', + headerName: 'Start Date', + flex: 1, + minWidth: 150, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return dayjs(params.row.campaign.startDate).format('DD/MM/YYYY'); + }, + }, + { + field: 'endDate', + headerName: 'End Date', + minWidth: 150, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + flex: 1, + sortable: false, + renderCell: (params: GridCellParams) => { + return ( +
    + {dayjs(params.row.campaign.endDate).format('DD/MM/YYYY')}{' '} +
    + ); + }, + }, + { + field: 'fundingGoal', + headerName: 'Funding Goal', + flex: 1, + minWidth: 100, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return ( +
    + { + currencySymbols[ + params.row.campaign.currency as keyof typeof currencySymbols + ] + } + {params.row.campaign.fundingGoal} +
    + ); + }, + }, + { + field: 'action', + headerName: 'Action', + flex: 1, + minWidth: 100, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return ( + <> + + + + ); + }, + }, + { + field: 'assocPledge', + headerName: 'Associated Pledges', + flex: 2, + minWidth: 100, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return ( + + ); + }, + }, + ]; + + return ( +
    + + navigate(`/orgfunds/${orgId}`)} + > + {tCommon('Funds')} + + FundRaising Campaign + + +
    +
    + setSearchTerm(e.target.value)} + data-testid="searchFullName" + /> + +
    +
    +
    + + + + {tCommon('sort')} + + + setSortBy('fundingGoal_ASC')} + data-testid="fundingGoal_ASC" + > + {t('lowestGoal')} + + setSortBy('fundingGoal_DESC')} + data-testid="fundingGoal_DESC" + > + {t('highestGoal')} + + setSortBy('endDate_DESC')} + data-testid="endDate_DESC" + > + {t('latestEndDate')} + + setSortBy('endDate_ASC')} + data-testid="endDate_ASC" + > + {t('earliestEndDate')} + + + +
    +
    + +
    +
    +
    + + row.campaign._id} + slots={{ + noRowsOverlay: () => ( + + {t('noCampaignsFound')} + + ), + }} + sx={dataGridStyle} + getRowClassName={() => `${styles.rowBackground}`} + autoHeight + rowHeight={65} + rows={campaigns.map((campaign, index) => ({ + id: index + 1, + campaign, + }))} + columns={columns} + isRowSelectable={() => false} + /> + + {/* Create Campaign ModalState */} + closeModal(ModalState.SAME)} + refetchCampaign={refetchCampaign} + fundId={fundId} + campaign={campaign} + mode={campaignModalMode} + /> + + closeModal(ModalState.DELETE)} + campaign={campaign} + refetchCampaign={refetchCampaign} + /> +
    + ); +}; +export default orgFundCampaign; diff --git a/src/screens/OrganizationFundCampaign/OrganizationFundCampaign.module.css b/src/screens/OrganizationFundCampaign/OrganizationFundCampaign.module.css new file mode 100644 index 0000000000..55202baef9 --- /dev/null +++ b/src/screens/OrganizationFundCampaign/OrganizationFundCampaign.module.css @@ -0,0 +1,202 @@ +.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/OrganizationFundCampaign/OrganizationFundCampaign.test.tsx b/src/screens/OrganizationFundCampaign/OrganizationFundCampaign.test.tsx new file mode 100644 index 0000000000..74f646f51a --- /dev/null +++ b/src/screens/OrganizationFundCampaign/OrganizationFundCampaign.test.tsx @@ -0,0 +1,336 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import type { RenderResult } from '@testing-library/react'; +import { + cleanup, + fireEvent, + render, + screen, + waitFor, +} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; +import { store } from '../../state/store'; +import { StaticMockLink } from '../../utils/StaticMockLink'; +import i18nForTest from '../../utils/i18nForTest'; +import OrganizaitionFundCampiagn from './OrganizationFundCampagins'; +import { + EMPTY_MOCKS, + MOCKS, + MOCK_ERROR, +} from './OrganizationFundCampaignMocks'; +import type { ApolloLink } from '@apollo/client'; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +jest.mock('@mui/x-date-pickers/DateTimePicker', () => { + return { + DateTimePicker: jest.requireActual( + '@mui/x-date-pickers/DesktopDateTimePicker', + ).DesktopDateTimePicker, + }; +}); + +const link1 = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(MOCK_ERROR, true); +const link3 = new StaticMockLink(EMPTY_MOCKS, true); + +const translations = JSON.parse( + JSON.stringify(i18nForTest.getDataByLanguage('en')?.translation.fundCampaign), +); + +const renderFundCampaign = (link: ApolloLink): RenderResult => { + return render( + + + + + + + } + /> +
    } + /> +
    } + /> + } + /> + + + + + + , + ); +}; + +describe('FundCampaigns Screen', () => { + beforeEach(() => { + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: 'orgId', fundId: 'fundId' }), + })); + }); + + afterEach(() => { + cleanup(); + }); + + afterAll(() => { + jest.clearAllMocks(); + }); + + it('should render the Campaign Pledge screen', async () => { + renderFundCampaign(link1); + await waitFor(() => { + expect(screen.getByTestId('searchFullName')).toBeInTheDocument(); + }); + + expect(screen.getByText('Campaign 1')).toBeInTheDocument(); + expect(screen.getByText('Campaign 2')).toBeInTheDocument(); + }); + + it('should redirect to fallback URL if URL params are undefined', async () => { + render( + + + + + + + } + /> + } + /> + + + + + + , + ); + await waitFor(() => { + expect(screen.getByTestId('paramsError')).toBeInTheDocument(); + }); + }); + + it('open and close Create Campaign modal', async () => { + renderFundCampaign(link1); + + const addCampaignBtn = await screen.findByTestId('addCampaignBtn'); + expect(addCampaignBtn).toBeInTheDocument(); + userEvent.click(addCampaignBtn); + + await waitFor(() => + expect(screen.getAllByText(translations.createCampaign)).toHaveLength(2), + ); + userEvent.click(screen.getByTestId('campaignCloseBtn')); + await waitFor(() => + expect(screen.queryByTestId('campaignCloseBtn')).toBeNull(), + ); + }); + + it('open and close update campaign modal', async () => { + renderFundCampaign(link1); + + await waitFor(() => { + expect(screen.getByTestId('searchFullName')).toBeInTheDocument(); + }); + + const editCampaignBtn = await screen.findAllByTestId('editCampaignBtn'); + await waitFor(() => expect(editCampaignBtn[0]).toBeInTheDocument()); + userEvent.click(editCampaignBtn[0]); + + await waitFor(() => + expect( + screen.getAllByText(translations.updateCampaign)[0], + ).toBeInTheDocument(), + ); + userEvent.click(screen.getByTestId('campaignCloseBtn')); + await waitFor(() => + expect(screen.queryByTestId('campaignCloseBtn')).toBeNull(), + ); + }); + + it('open and closes delete campaign modal', async () => { + renderFundCampaign(link1); + + const deleteCampaignBtn = await screen.findAllByTestId('deleteCampaignBtn'); + await waitFor(() => expect(deleteCampaignBtn[0]).toBeInTheDocument()); + userEvent.click(deleteCampaignBtn[0]); + + await waitFor(() => + expect(screen.getByText(translations.deleteCampaign)).toBeInTheDocument(), + ); + userEvent.click(screen.getByTestId('deleteCampaignCloseBtn')); + await waitFor(() => + expect(screen.queryByTestId('deleteCampaignCloseBtn')).toBeNull(), + ); + }); + + it('Search the Campaigns list by Name', async () => { + renderFundCampaign(link1); + const searchField = await screen.findByTestId('searchFullName'); + fireEvent.change(searchField, { + target: { value: '2' }, + }); + + await waitFor(() => { + expect(screen.getByText('Campaign 2')).toBeInTheDocument(); + expect(screen.queryByText('Campaign 1')).toBeNull(); + }); + }); + + it('should render the Campaign screen with error', async () => { + renderFundCampaign(link2); + await waitFor(() => { + expect(screen.getByTestId('errorMsg')).toBeInTheDocument(); + }); + }); + + it('renders the empty campaign component', async () => { + renderFundCampaign(link3); + await waitFor(() => + expect( + screen.getByText(translations.noCampaignsFound), + ).toBeInTheDocument(), + ); + }); + + it('Sort the Campaigns list by Latest end Date', async () => { + renderFundCampaign(link1); + + const sortBtn = await screen.findByTestId('filter'); + expect(sortBtn).toBeInTheDocument(); + + fireEvent.click(sortBtn); + fireEvent.click(screen.getByTestId('endDate_DESC')); + + await waitFor(() => { + expect(screen.getByText('Campaign 1')).toBeInTheDocument(); + expect(screen.queryByText('Campaign 2')).toBeInTheDocument(); + }); + + await waitFor(() => { + expect(screen.getAllByTestId('endDateCell')[0]).toHaveTextContent( + '01/01/2024', + ); + }); + }); + + it('Sort the Campaigns list by Earliest end Date', async () => { + renderFundCampaign(link1); + + const sortBtn = await screen.findByTestId('filter'); + expect(sortBtn).toBeInTheDocument(); + + fireEvent.click(sortBtn); + fireEvent.click(screen.getByTestId('endDate_ASC')); + + await waitFor(() => { + expect(screen.getByText('Campaign 1')).toBeInTheDocument(); + expect(screen.queryByText('Campaign 2')).toBeInTheDocument(); + }); + + await waitFor(() => { + expect(screen.getAllByTestId('endDateCell')[0]).toHaveTextContent( + '01/01/2021', + ); + }); + }); + + it('Sort the Campaigns list by lowest goal', async () => { + renderFundCampaign(link1); + + const sortBtn = await screen.findByTestId('filter'); + expect(sortBtn).toBeInTheDocument(); + + fireEvent.click(sortBtn); + fireEvent.click(screen.getByTestId('fundingGoal_ASC')); + + await waitFor(() => { + expect(screen.getByText('Campaign 1')).toBeInTheDocument(); + expect(screen.queryByText('Campaign 2')).toBeInTheDocument(); + }); + + await waitFor(() => { + expect(screen.getAllByTestId('goalCell')[0]).toHaveTextContent('100'); + }); + }); + + it('Sort the Campaigns list by highest goal', async () => { + renderFundCampaign(link1); + + const sortBtn = await screen.findByTestId('filter'); + expect(sortBtn).toBeInTheDocument(); + + fireEvent.click(sortBtn); + fireEvent.click(screen.getByTestId('fundingGoal_DESC')); + + await waitFor(() => { + expect(screen.getByText('Campaign 1')).toBeInTheDocument(); + expect(screen.queryByText('Campaign 2')).toBeInTheDocument(); + }); + + await waitFor(() => { + expect(screen.getAllByTestId('goalCell')[0]).toHaveTextContent('200'); + }); + }); + + it('Click on Campaign Name', async () => { + renderFundCampaign(link1); + + const campaignName = await screen.findAllByTestId('campaignName'); + expect(campaignName[0]).toBeInTheDocument(); + fireEvent.click(campaignName[0]); + + await waitFor(() => { + expect(screen.getByTestId('pledgeScreen')).toBeInTheDocument(); + }); + }); + + it('Click on View Pledge', async () => { + renderFundCampaign(link1); + + const viewBtn = await screen.findAllByTestId('viewBtn'); + expect(viewBtn[0]).toBeInTheDocument(); + fireEvent.click(viewBtn[0]); + + await waitFor(() => { + expect(screen.getByTestId('pledgeScreen')).toBeInTheDocument(); + }); + }); + + it('should render the Fund screen on fund breadcrumb click', async () => { + renderFundCampaign(link1); + + const fundBreadcrumb = await screen.findByTestId('fundsLink'); + expect(fundBreadcrumb).toBeInTheDocument(); + fireEvent.click(fundBreadcrumb); + + await waitFor(() => { + expect(screen.getByTestId('fundScreen')).toBeInTheDocument(); + }); + }); +}); diff --git a/src/screens/OrganizationFundCampaign/OrganizationFundCampaignMocks.ts b/src/screens/OrganizationFundCampaign/OrganizationFundCampaignMocks.ts new file mode 100644 index 0000000000..160dfad5fb --- /dev/null +++ b/src/screens/OrganizationFundCampaign/OrganizationFundCampaignMocks.ts @@ -0,0 +1,329 @@ +import { + CREATE_CAMPAIGN_MUTATION, + DELETE_CAMPAIGN_MUTATION, + UPDATE_CAMPAIGN_MUTATION, +} from 'GraphQl/Mutations/CampaignMutation'; +import { FUND_CAMPAIGN } from 'GraphQl/Queries/fundQueries'; + +export const MOCKS = [ + { + request: { + query: FUND_CAMPAIGN, + variables: { + id: 'fundId', + orderBy: null, + where: { name_contains: '' }, + }, + }, + result: { + data: { + getFundById: { + campaigns: [ + { + _id: 'campaignId1', + name: 'Campaign 1', + fundingGoal: 100, + startDate: '2024-01-01', + endDate: '2024-01-01', + currency: 'USD', + }, + { + _id: '2', + name: 'Campaign 2', + fundingGoal: 200, + startDate: '2021-01-01', + endDate: '2021-01-01', + currency: 'USD', + }, + ], + }, + }, + }, + }, + { + request: { + query: FUND_CAMPAIGN, + variables: { + id: 'fundId', + orderBy: null, + where: { name_contains: '2' }, + }, + }, + result: { + data: { + getFundById: { + campaigns: [ + { + _id: '2', + name: 'Campaign 2', + fundingGoal: 200, + startDate: '2021-01-01', + endDate: '2021-01-01', + currency: 'USD', + }, + ], + }, + }, + }, + }, + { + request: { + query: FUND_CAMPAIGN, + variables: { + id: 'fundId', + orderBy: 'endDate_DESC', + where: { name_contains: '' }, + }, + }, + result: { + data: { + getFundById: { + campaigns: [ + { + _id: '1', + name: 'Campaign 1', + fundingGoal: 100, + startDate: '2024-01-01', + endDate: '2024-01-01', + currency: 'USD', + }, + { + _id: '2', + name: 'Campaign 2', + fundingGoal: 200, + startDate: '2021-01-01', + endDate: '2021-01-01', + currency: 'USD', + }, + ], + }, + }, + }, + }, + { + request: { + query: FUND_CAMPAIGN, + variables: { + id: 'fundId', + orderBy: 'endDate_ASC', + where: { name_contains: '' }, + }, + }, + result: { + data: { + getFundById: { + campaigns: [ + { + _id: '2', + name: 'Campaign 2', + fundingGoal: 200, + startDate: '2021-01-01', + endDate: '2021-01-01', + currency: 'USD', + }, + { + _id: '1', + name: 'Campaign 1', + fundingGoal: 100, + startDate: '2024-01-01', + endDate: '2024-01-01', + currency: 'USD', + }, + ], + }, + }, + }, + }, + { + request: { + query: FUND_CAMPAIGN, + variables: { + id: 'fundId', + orderBy: 'fundingGoal_DESC', + where: { name_contains: '' }, + }, + }, + result: { + data: { + getFundById: { + campaigns: [ + { + _id: '2', + name: 'Campaign 2', + fundingGoal: 200, + startDate: '2021-01-01', + endDate: '2021-01-01', + currency: 'USD', + }, + { + _id: '1', + name: 'Campaign 1', + fundingGoal: 100, + startDate: '2024-01-01', + endDate: '2024-01-01', + currency: 'USD', + }, + ], + }, + }, + }, + }, + { + request: { + query: FUND_CAMPAIGN, + variables: { + id: 'fundId', + orderBy: 'fundingGoal_ASC', + where: { name_contains: '' }, + }, + }, + result: { + data: { + getFundById: { + campaigns: [ + { + _id: '1', + name: 'Campaign 1', + fundingGoal: 100, + startDate: '2024-01-01', + endDate: '2024-01-01', + currency: 'USD', + }, + { + _id: '2', + name: 'Campaign 2', + fundingGoal: 200, + startDate: '2021-01-01', + endDate: '2021-01-01', + currency: 'USD', + }, + ], + }, + }, + }, + }, + { + request: { + query: CREATE_CAMPAIGN_MUTATION, + variables: { + fundId: 'fundId', + name: 'Campaign 2', + fundingGoal: 200, + startDate: '2024-01-02', + endDate: '2024-02-02', + currency: 'USD', + }, + }, + result: { + data: { + createFundraisingCampaign: { + _id: 'fundId', + }, + }, + }, + }, + { + request: { + query: UPDATE_CAMPAIGN_MUTATION, + variables: { + id: 'campaignId1', + name: 'Campaign 4', + fundingGoal: 400, + startDate: '2023-01-02', + endDate: '2023-02-02', + }, + }, + result: { + data: { + updateFundraisingCampaign: { + _id: 'campaignId1', + }, + }, + }, + }, + { + request: { + query: DELETE_CAMPAIGN_MUTATION, + variables: { + id: 'campaignId1', + }, + }, + result: { + data: { + removeFundraisingCampaign: { + _id: 'campaignId1', + }, + }, + }, + }, +]; + +export const MOCK_ERROR = [ + { + request: { + query: FUND_CAMPAIGN, + variables: { + id: 'fundId', + orderBy: null, + where: { name_contains: '2' }, + }, + }, + error: new Error('An error occurred'), + }, + { + request: { + query: CREATE_CAMPAIGN_MUTATION, + variables: { + fundId: 'fundId', + name: 'Campaign 2', + fundingGoal: 200, + startDate: '2024-01-02', + endDate: '2024-02-02', + currency: 'USD', + }, + }, + error: new Error('Mock graphql error'), + }, + { + request: { + query: UPDATE_CAMPAIGN_MUTATION, + variables: { + id: 'campaignId1', + name: 'Campaign 4', + fundingGoal: 400, + startDate: '2023-01-02', + endDate: '2023-02-02', + }, + }, + error: new Error('Mock graphql error'), + }, + { + request: { + query: DELETE_CAMPAIGN_MUTATION, + variables: { + id: 'campaignId1', + }, + }, + error: new Error('Mock graphql error'), + }, +]; + +export const EMPTY_MOCKS = [ + { + request: { + query: FUND_CAMPAIGN, + variables: { + id: 'fundId', + orderBy: null, + where: { name_contains: '' }, + }, + }, + result: { + data: { + getFundById: { + campaigns: [], + }, + }, + }, + }, +]; diff --git a/src/screens/OrganizationFunds/FundDeleteModal.test.tsx b/src/screens/OrganizationFunds/FundDeleteModal.test.tsx new file mode 100644 index 0000000000..41fcd3ec5e --- /dev/null +++ b/src/screens/OrganizationFunds/FundDeleteModal.test.tsx @@ -0,0 +1,100 @@ +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 i18nForTest from '../../utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { toast } from 'react-toastify'; +import type { InterfaceDeleteFundModal } from './FundDeleteModal'; +import FundDeleteModal from './FundDeleteModal'; +import { MOCKS, MOCKS_ERROR } from './OrganizationFundsMocks'; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +const link1 = new StaticMockLink(MOCKS); +const link2 = new StaticMockLink(MOCKS_ERROR); +const translations = JSON.parse( + JSON.stringify(i18nForTest.getDataByLanguage('en')?.translation.funds), +); + +const fundProps: InterfaceDeleteFundModal = { + isOpen: true, + hide: jest.fn(), + fund: { + _id: 'fundId', + name: 'Fund 1', + refrenceNumber: '1111', + taxDeductible: true, + isArchived: false, + isDefault: false, + createdAt: '2024-06-22', + organizationId: 'orgId', + creator: { + _id: 'creatorId1', + firstName: 'John', + lastName: 'Doe', + }, + }, + refetchFunds: jest.fn(), +}; +const renderFundDeleteModal = ( + link: ApolloLink, + props: InterfaceDeleteFundModal, +): RenderResult => { + return render( + + + + + + + + + + + , + ); +}; + +describe('FundDeleteModal', () => { + it('should render FundDeleteModal', () => { + renderFundDeleteModal(link1, fundProps); + expect(screen.getByTestId('deleteFundCloseBtn')).toBeInTheDocument(); + }); + + it('should successfully Delete Fund', async () => { + renderFundDeleteModal(link1, fundProps); + expect(screen.getByTestId('deleteFundCloseBtn')).toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('deleteyesbtn')); + + await waitFor(() => { + expect(fundProps.refetchFunds).toHaveBeenCalled(); + expect(fundProps.hide).toHaveBeenCalled(); + expect(toast.success).toHaveBeenCalledWith(translations.fundDeleted); + }); + }); + + it('should fail to Delete Fund', async () => { + renderFundDeleteModal(link2, fundProps); + expect(screen.getByTestId('deleteFundCloseBtn')).toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('deleteyesbtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith('Mock graphql error'); + }); + }); +}); diff --git a/src/screens/OrganizationFunds/FundDeleteModal.tsx b/src/screens/OrganizationFunds/FundDeleteModal.tsx new file mode 100644 index 0000000000..fb13206f1a --- /dev/null +++ b/src/screens/OrganizationFunds/FundDeleteModal.tsx @@ -0,0 +1,79 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import type { InterfaceFundInfo } from 'utils/interfaces'; +import styles from './OrganizationFunds.module.css'; +import { Button, Modal } from 'react-bootstrap'; +import { REMOVE_FUND_MUTATION } from 'GraphQl/Mutations/FundMutation'; +import { useMutation } from '@apollo/client'; +import { toast } from 'react-toastify'; + +export interface InterfaceDeleteFundModal { + isOpen: boolean; + hide: () => void; + fund: InterfaceFundInfo | null; + refetchFunds: () => void; +} + +const FundDeleteModal: React.FC = ({ + isOpen, + hide, + fund, + refetchFunds, +}) => { + const { t } = useTranslation('translation', { + keyPrefix: 'funds', + }); + const { t: tCommon } = useTranslation('common'); + + const [deleteFund] = useMutation(REMOVE_FUND_MUTATION); + + const deleteFundHandler = async (): Promise => { + try { + await deleteFund({ + variables: { + id: fund?._id, + }, + }); + refetchFunds(); + hide(); + toast.success(t('fundDeleted')); + } catch (error: unknown) { + toast.error((error as Error).message); + } + }; + + return ( + <> + + +

    {t('fundDelete')}

    + +
    + +

    {t('deleteFundMsg')}

    +
    + + + + +
    + + ); +}; + +export default FundDeleteModal; diff --git a/src/screens/OrganizationFunds/FundModal.test.tsx b/src/screens/OrganizationFunds/FundModal.test.tsx new file mode 100644 index 0000000000..c74b0434c3 --- /dev/null +++ b/src/screens/OrganizationFunds/FundModal.test.tsx @@ -0,0 +1,260 @@ +import React from 'react'; +import type { ApolloLink } from '@apollo/client'; +import { MockedProvider } from '@apollo/react-testing'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import type { RenderResult } from '@testing-library/react'; +import { + cleanup, + fireEvent, + render, + screen, + waitFor, +} from '@testing-library/react'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { store } from 'state/store'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import i18nForTest from '../../utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { toast } from 'react-toastify'; +import { MOCKS, MOCKS_ERROR } from './OrganizationFundsMocks'; +import type { InterfaceFundModal } from './FundModal'; +import FundModal from './FundModal'; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +const link1 = new StaticMockLink(MOCKS); +const link2 = new StaticMockLink(MOCKS_ERROR); +const translations = JSON.parse( + JSON.stringify(i18nForTest.getDataByLanguage('en')?.translation.funds), +); + +const fundProps: InterfaceFundModal[] = [ + { + isOpen: true, + hide: jest.fn(), + fund: { + _id: 'fundId', + name: 'Fund 1', + refrenceNumber: '1111', + taxDeductible: true, + isArchived: false, + isDefault: false, + createdAt: '2024-06-22', + organizationId: 'orgId', + creator: { + _id: 'creatorId1', + firstName: 'John', + lastName: 'Doe', + }, + }, + refetchFunds: jest.fn(), + orgId: 'orgId', + mode: 'create', + }, + { + isOpen: true, + hide: jest.fn(), + fund: { + _id: 'fundId', + name: 'Fund 1', + refrenceNumber: '1111', + taxDeductible: true, + isArchived: false, + isDefault: false, + createdAt: '2024-06-22', + organizationId: 'orgId', + creator: { + _id: 'creatorId1', + firstName: 'John', + lastName: 'Doe', + }, + }, + refetchFunds: jest.fn(), + orgId: 'orgId', + mode: 'edit', + }, +]; + +const renderFundModal = ( + link: ApolloLink, + props: InterfaceFundModal, +): RenderResult => { + return render( + + + + + + + + + + + , + ); +}; + +describe('PledgeModal', () => { + afterEach(() => { + cleanup(); + }); + + it('should populate form fields with correct values in edit mode', async () => { + renderFundModal(link1, fundProps[1]); + await waitFor(() => + expect( + screen.getAllByText(translations.fundUpdate)[0], + ).toBeInTheDocument(), + ); + expect(screen.getByLabelText(translations.fundName)).toHaveValue('Fund 1'); + expect(screen.getByLabelText(translations.fundId)).toHaveValue('1111'); + expect(screen.getByTestId('setTaxDeductibleSwitch')).toBeChecked(); + expect(screen.getByTestId('setDefaultSwitch')).not.toBeChecked(); + expect(screen.getByTestId('archivedSwitch')).not.toBeChecked(); + }); + + it('should update Fund Name when input value changes', async () => { + renderFundModal(link1, fundProps[1]); + const fundNameInput = screen.getByLabelText(translations.fundName); + expect(fundNameInput).toHaveValue('Fund 1'); + fireEvent.change(fundNameInput, { target: { value: 'Fund 2' } }); + expect(fundNameInput).toHaveValue('Fund 2'); + }); + + it('should update Fund Reference ID when input value changes', async () => { + renderFundModal(link1, fundProps[1]); + const fundIdInput = screen.getByLabelText(translations.fundId); + expect(fundIdInput).toHaveValue('1111'); + fireEvent.change(fundIdInput, { target: { value: '2222' } }); + expect(fundIdInput).toHaveValue('2222'); + }); + + it('should update Tax Deductible Switch when input value changes', async () => { + renderFundModal(link1, fundProps[1]); + const taxDeductibleSwitch = screen.getByTestId('setTaxDeductibleSwitch'); + expect(taxDeductibleSwitch).toBeChecked(); + fireEvent.click(taxDeductibleSwitch); + expect(taxDeductibleSwitch).not.toBeChecked(); + }); + + it('should update Tax Default switch when input value changes', async () => { + renderFundModal(link1, fundProps[1]); + const defaultSwitch = screen.getByTestId('setDefaultSwitch'); + expect(defaultSwitch).not.toBeChecked(); + fireEvent.click(defaultSwitch); + expect(defaultSwitch).toBeChecked(); + }); + + it('should update Tax isArchived switch when input value changes', async () => { + renderFundModal(link1, fundProps[1]); + const archivedSwitch = screen.getByTestId('archivedSwitch'); + expect(archivedSwitch).not.toBeChecked(); + fireEvent.click(archivedSwitch); + expect(archivedSwitch).toBeChecked(); + }); + + it('should create fund', async () => { + renderFundModal(link1, fundProps[0]); + + const fundNameInput = screen.getByLabelText(translations.fundName); + fireEvent.change(fundNameInput, { target: { value: 'Fund 2' } }); + + const fundIdInput = screen.getByLabelText(translations.fundId); + fireEvent.change(fundIdInput, { target: { value: '2222' } }); + + const taxDeductibleSwitch = screen.getByTestId('setTaxDeductibleSwitch'); + fireEvent.click(taxDeductibleSwitch); + + const defaultSwitch = screen.getByTestId('setDefaultSwitch'); + fireEvent.click(defaultSwitch); + + fireEvent.click(screen.getByTestId('createFundFormSubmitBtn')); + + await waitFor(() => { + expect(toast.success).toHaveBeenCalledWith(translations.fundCreated); + expect(fundProps[0].refetchFunds).toHaveBeenCalled(); + expect(fundProps[0].hide).toHaveBeenCalled(); + }); + }); + + it('should update fund', async () => { + renderFundModal(link1, fundProps[1]); + + const fundNameInput = screen.getByLabelText(translations.fundName); + fireEvent.change(fundNameInput, { target: { value: 'Fund 2' } }); + + const fundIdInput = screen.getByLabelText(translations.fundId); + fireEvent.change(fundIdInput, { target: { value: '2222' } }); + + const taxDeductibleSwitch = screen.getByTestId('setTaxDeductibleSwitch'); + fireEvent.click(taxDeductibleSwitch); + + const defaultSwitch = screen.getByTestId('setDefaultSwitch'); + fireEvent.click(defaultSwitch); + + const archivedSwitch = screen.getByTestId('archivedSwitch'); + fireEvent.click(archivedSwitch); + + fireEvent.click(screen.getByTestId('createFundFormSubmitBtn')); + + await waitFor(() => { + expect(toast.success).toHaveBeenCalledWith(translations.fundUpdated); + expect(fundProps[1].refetchFunds).toHaveBeenCalled(); + expect(fundProps[1].hide).toHaveBeenCalled(); + }); + }); + + it('Error: should create fund', async () => { + renderFundModal(link2, fundProps[0]); + + const fundNameInput = screen.getByLabelText(translations.fundName); + fireEvent.change(fundNameInput, { target: { value: 'Fund 2' } }); + + const fundIdInput = screen.getByLabelText(translations.fundId); + fireEvent.change(fundIdInput, { target: { value: '2222' } }); + + const taxDeductibleSwitch = screen.getByTestId('setTaxDeductibleSwitch'); + fireEvent.click(taxDeductibleSwitch); + + const defaultSwitch = screen.getByTestId('setDefaultSwitch'); + fireEvent.click(defaultSwitch); + + fireEvent.click(screen.getByTestId('createFundFormSubmitBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith('Mock graphql error'); + }); + }); + + it('Error: should update fund', async () => { + renderFundModal(link2, fundProps[1]); + + const fundNameInput = screen.getByLabelText(translations.fundName); + fireEvent.change(fundNameInput, { target: { value: 'Fund 2' } }); + + const fundIdInput = screen.getByLabelText(translations.fundId); + fireEvent.change(fundIdInput, { target: { value: '2222' } }); + + const taxDeductibleSwitch = screen.getByTestId('setTaxDeductibleSwitch'); + fireEvent.click(taxDeductibleSwitch); + + const defaultSwitch = screen.getByTestId('setDefaultSwitch'); + fireEvent.click(defaultSwitch); + + const archivedSwitch = screen.getByTestId('archivedSwitch'); + fireEvent.click(archivedSwitch); + + fireEvent.click(screen.getByTestId('createFundFormSubmitBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith('Mock graphql error'); + }); + }); +}); diff --git a/src/screens/OrganizationFunds/FundModal.tsx b/src/screens/OrganizationFunds/FundModal.tsx new file mode 100644 index 0000000000..f4c6350a1c --- /dev/null +++ b/src/screens/OrganizationFunds/FundModal.tsx @@ -0,0 +1,258 @@ +import React, { useEffect, useState } from 'react'; +import type { ChangeEvent } from 'react'; +import { Button, Form, Modal } from 'react-bootstrap'; +import type { InterfaceCreateFund, InterfaceFundInfo } from 'utils/interfaces'; +import styles from './OrganizationFunds.module.css'; +import { useTranslation } from 'react-i18next'; +import { useMutation } from '@apollo/client'; +import { + CREATE_FUND_MUTATION, + UPDATE_FUND_MUTATION, +} from 'GraphQl/Mutations/FundMutation'; +import { toast } from 'react-toastify'; +import { FormControl, TextField } from '@mui/material'; + +export interface InterfaceFundModal { + isOpen: boolean; + hide: () => void; + refetchFunds: () => void; + fund: InterfaceFundInfo | null; + orgId: string; + mode: 'create' | 'edit'; +} + +const FundModal: React.FC = ({ + isOpen, + hide, + refetchFunds, + fund, + orgId, + mode, +}) => { + const { t } = useTranslation('translation', { + keyPrefix: 'funds', + }); + + const [formState, setFormState] = useState({ + fundName: fund?.name ?? '', + fundRef: fund?.refrenceNumber ?? '', + isDefault: fund?.isDefault ?? false, + taxDeductible: fund?.taxDeductible ?? false, + isArchived: fund?.isArchived ?? false, + }); + + useEffect(() => { + setFormState({ + fundName: fund?.name ?? '', + fundRef: fund?.refrenceNumber ?? '', + isDefault: fund?.isDefault ?? false, + taxDeductible: fund?.taxDeductible ?? false, + isArchived: fund?.isArchived ?? false, + }); + }, [fund]); + + const [createFund] = useMutation(CREATE_FUND_MUTATION); + const [updateFund] = useMutation(UPDATE_FUND_MUTATION); + + const createFundHandler = async ( + e: ChangeEvent, + ): Promise => { + e.preventDefault(); + const { fundName, fundRef, isDefault, taxDeductible, isArchived } = + formState; + try { + await createFund({ + variables: { + name: fundName, + refrenceNumber: fundRef, + organizationId: orgId, + taxDeductible, + isArchived, + isDefault, + }, + }); + + setFormState({ + fundName: '', + fundRef: '', + isDefault: false, + taxDeductible: false, + isArchived: false, + }); + toast.success(t('fundCreated')); + refetchFunds(); + hide(); + } catch (error: unknown) { + toast.error((error as Error).message); + } + }; + + /*istanbul ignore next*/ + const updateFundHandler = async ( + e: ChangeEvent, + ): Promise => { + e.preventDefault(); + const { fundName, fundRef, taxDeductible, isArchived, isDefault } = + formState; + try { + const updatedFields: { [key: string]: string | boolean } = {}; + if (fundName != fund?.name) { + updatedFields.name = fundName; + } + if (fundRef != fund?.refrenceNumber) { + updatedFields.refrenceNumber = fundRef; + } + if (taxDeductible != fund?.taxDeductible) { + updatedFields.taxDeductible = taxDeductible; + } + if (isArchived != fund?.isArchived) { + updatedFields.isArchived = isArchived; + } + if (isDefault != fund?.isDefault) { + updatedFields.isDefault = isDefault; + } + + await updateFund({ + variables: { + id: fund?._id, + ...updatedFields, + }, + }); + setFormState({ + fundName: '', + fundRef: '', + isDefault: false, + taxDeductible: false, + isArchived: false, + }); + refetchFunds(); + hide(); + toast.success(t('fundUpdated')); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + } + } + }; + + return ( + <> + + +

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

    + +
    + +
    + + + + setFormState({ + ...formState, + fundName: e.target.value, + }) + } + /> + + + + + + setFormState({ + ...formState, + fundRef: e.target.value, + }) + } + /> + + + +
    + + + + setFormState({ + ...formState, + taxDeductible: !formState.taxDeductible, + }) + } + /> + + + + + setFormState({ + ...formState, + isDefault: !formState.isDefault, + }) + } + /> + + {mode === 'edit' && ( + + + + setFormState({ + ...formState, + isArchived: !formState.isArchived, + }) + } + /> + + )} +
    + +
    +
    +
    + + ); +}; +export default FundModal; diff --git a/src/screens/OrganizationFunds/OrganizationFunds.module.css b/src/screens/OrganizationFunds/OrganizationFunds.module.css new file mode 100644 index 0000000000..aa9d89dfb1 --- /dev/null +++ b/src/screens/OrganizationFunds/OrganizationFunds.module.css @@ -0,0 +1,142 @@ +.list_box { + height: auto; + overflow-y: auto; + width: 100%; +} + +.inputField { + margin-top: 10px; + margin-bottom: 10px; + background-color: white; + box-shadow: 0 1px 1px #31bb6b; +} + +.inputField > button { + padding-top: 10px; + padding-bottom: 10px; +} + +.dropdown { + background-color: white; + border: 1px solid #31bb6b; + position: relative; + display: inline-block; + color: #31bb6b; +} + +.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; +} + +.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%; +} + +.manageBtn { + margin: 1rem 0 0; + margin-top: 15px; + border: 1px solid #e8e5e5; + box-shadow: 0 2px 2px #e8e5e5; + padding: 10px 10px; + border-radius: 5px; + font-size: 16px; + color: white; + outline: none; + font-weight: 600; + cursor: pointer; + width: 45%; + transition: + transform 0.2s, + box-shadow 0.2s; +} + +.btnsContainer { + display: flex; + margin: 2rem 0 2.5rem 0; +} + +.btnsContainer .input { + flex: 1; + min-width: 18rem; + 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; +} + +.rowBackground { + background-color: var(--bs-white); + max-height: 120px; +} + +.tableHeader { + background-color: var(--bs-primary); + color: var(--bs-white); + font-size: 1rem; +} diff --git a/src/screens/OrganizationFunds/OrganizationFunds.test.tsx b/src/screens/OrganizationFunds/OrganizationFunds.test.tsx new file mode 100644 index 0000000000..a1b49e68eb --- /dev/null +++ b/src/screens/OrganizationFunds/OrganizationFunds.test.tsx @@ -0,0 +1,260 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/client/testing'; +import type { RenderResult } from '@testing-library/react'; +import { + cleanup, + fireEvent, + render, + screen, + waitFor, +} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18nForTest from 'utils/i18nForTest'; +import OrganizationFunds from './OrganizationFunds'; +import { MOCKS, MOCKS_ERROR, NO_FUNDS } from './OrganizationFundsMocks'; +import type { ApolloLink } from '@apollo/client'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +const link1 = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(MOCKS_ERROR, true); +const link3 = new StaticMockLink(NO_FUNDS, true); + +const translations = JSON.parse( + JSON.stringify(i18nForTest.getDataByLanguage('en')?.translation.funds), +); + +const renderOrganizationFunds = (link: ApolloLink): RenderResult => { + return render( + + + + + + + } + /> + } + /> + } + /> + + + + + + , + ); +}; + +describe('OrganizationFunds Screen =>', () => { + beforeEach(() => { + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: 'orgId' }), + })); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + afterEach(() => { + cleanup(); + }); + + it('should render the Campaign Pledge screen', async () => { + renderOrganizationFunds(link1); + await waitFor(() => { + expect(screen.getByTestId('searchByName')).toBeInTheDocument(); + }); + }); + + it('should redirect to fallback URL if URL params are undefined', async () => { + render( + + + + + + } /> + } + /> + + + + + , + ); + await waitFor(() => { + expect(screen.getByTestId('paramsError')).toBeInTheDocument(); + }); + }); + + it('open and close Create Fund modal', async () => { + renderOrganizationFunds(link1); + + const createFundBtn = await screen.findByTestId('createFundBtn'); + expect(createFundBtn).toBeInTheDocument(); + userEvent.click(createFundBtn); + + await waitFor(() => + expect(screen.getAllByText(translations.fundCreate)).toHaveLength(3), + ); + userEvent.click(screen.getByTestId('fundModalCloseBtn')); + await waitFor(() => + expect(screen.queryByTestId('fundModalCloseBtn')).toBeNull(), + ); + }); + + it('open and close update fund modal', async () => { + renderOrganizationFunds(link1); + + await waitFor(() => { + expect(screen.getByTestId('searchByName')).toBeInTheDocument(); + }); + + const editFundBtn = await screen.findAllByTestId('editFundBtn'); + await waitFor(() => expect(editFundBtn[0]).toBeInTheDocument()); + userEvent.click(editFundBtn[0]); + + await waitFor(() => + expect( + screen.getAllByText(translations.fundUpdate)[0], + ).toBeInTheDocument(), + ); + userEvent.click(screen.getByTestId('fundModalCloseBtn')); + await waitFor(() => + expect(screen.queryByTestId('fundModalCloseBtn')).toBeNull(), + ); + }); + + it('open and closes delete fund modal', async () => { + renderOrganizationFunds(link1); + + const deleteFundBtn = await screen.findAllByTestId('deleteFundBtn'); + await waitFor(() => expect(deleteFundBtn[0]).toBeInTheDocument()); + userEvent.click(deleteFundBtn[0]); + + await waitFor(() => + expect(screen.getByText(translations.fundDelete)).toBeInTheDocument(), + ); + userEvent.click(screen.getByTestId('deleteFundCloseBtn')); + await waitFor(() => + expect(screen.queryByTestId('deleteFundCloseBtn')).toBeNull(), + ); + }); + + it('Search the Funds list by name', async () => { + renderOrganizationFunds(link1); + const searchField = await screen.findByTestId('searchByName'); + fireEvent.change(searchField, { + target: { value: '2' }, + }); + + await waitFor(() => { + expect(screen.getByText('Fund 2')).toBeInTheDocument(); + expect(screen.queryByText('Fund 1')).toBeNull(); + }); + }); + + it('should render the Fund screen with error', async () => { + renderOrganizationFunds(link2); + await waitFor(() => { + expect(screen.getByTestId('errorMsg')).toBeInTheDocument(); + }); + }); + + it('renders the empty fund component', async () => { + renderOrganizationFunds(link3); + await waitFor(() => + expect(screen.getByText(translations.noFundsFound)).toBeInTheDocument(), + ); + }); + + it('Sort the Pledges list by Latest created Date', async () => { + renderOrganizationFunds(link1); + + const sortBtn = await screen.findByTestId('filter'); + expect(sortBtn).toBeInTheDocument(); + + fireEvent.click(sortBtn); + fireEvent.click(screen.getByTestId('createdAt_DESC')); + + await waitFor(() => { + expect(screen.getByText('Fund 1')).toBeInTheDocument(); + expect(screen.queryByText('Fund 2')).toBeInTheDocument(); + }); + + await waitFor(() => { + expect(screen.getAllByTestId('createdOn')[0]).toHaveTextContent( + '22/06/2024', + ); + }); + }); + + it('Sort the Pledges list by Earliest created Date', async () => { + renderOrganizationFunds(link1); + + const sortBtn = await screen.findByTestId('filter'); + expect(sortBtn).toBeInTheDocument(); + + fireEvent.click(sortBtn); + fireEvent.click(screen.getByTestId('createdAt_ASC')); + + await waitFor(() => { + expect(screen.getByText('Fund 1')).toBeInTheDocument(); + expect(screen.queryByText('Fund 2')).toBeInTheDocument(); + }); + + await waitFor(() => { + expect(screen.getAllByTestId('createdOn')[0]).toHaveTextContent( + '21/06/2024', + ); + }); + }); + + it('Click on Fund Name', async () => { + renderOrganizationFunds(link1); + + const fundName = await screen.findAllByTestId('fundName'); + expect(fundName[0]).toBeInTheDocument(); + fireEvent.click(fundName[0]); + + await waitFor(() => { + expect(screen.getByTestId('campaignScreen')).toBeInTheDocument(); + }); + }); + + it('Click on View Campaign', async () => { + renderOrganizationFunds(link1); + + const viewBtn = await screen.findAllByTestId('viewBtn'); + expect(viewBtn[0]).toBeInTheDocument(); + fireEvent.click(viewBtn[0]); + + await waitFor(() => { + expect(screen.getByTestId('campaignScreen')).toBeInTheDocument(); + }); + }); +}); diff --git a/src/screens/OrganizationFunds/OrganizationFunds.tsx b/src/screens/OrganizationFunds/OrganizationFunds.tsx new file mode 100644 index 0000000000..4357877105 --- /dev/null +++ b/src/screens/OrganizationFunds/OrganizationFunds.tsx @@ -0,0 +1,390 @@ +import { useQuery } from '@apollo/client'; +import { Search, Sort, WarningAmberRounded } from '@mui/icons-material'; +import { Stack } from '@mui/material'; +import { + DataGrid, + type GridCellParams, + type GridColDef, +} from '@mui/x-data-grid'; +import { Button, Dropdown, Form } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; +import { Navigate, useNavigate, useParams } from 'react-router-dom'; +import React, { useCallback, useMemo, useState } from 'react'; +import dayjs from 'dayjs'; +import Loader from 'components/Loader/Loader'; +import FundModal from './FundModal'; +import FundDeleteModal from './FundDeleteModal'; +import { FUND_LIST } from 'GraphQl/Queries/fundQueries'; +import styles from './OrganizationFunds.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', + }, + '& .MuiDataGrid-row:hover': { + backgroundColor: 'transparent', + }, + '& .MuiDataGrid-row.Mui-hovered': { + backgroundColor: 'transparent', + }, + '& .MuiDataGrid-root': { + borderRadius: '0.5rem', + }, + '& .MuiDataGrid-main': { + borderRadius: '0.5rem', + }, +}; + +enum ModalState { + SAME = 'same', + DELETE = 'delete', +} + +const organizationFunds = (): JSX.Element => { + const { t } = useTranslation('translation', { + keyPrefix: 'funds', + }); + const { t: tCommon } = useTranslation('common'); + + const { orgId } = useParams(); + const navigate = useNavigate(); + + if (!orgId) { + return ; + } + + const [fund, setFund] = useState(null); + const [searchTerm, setSearchTerm] = useState(''); + const [sortBy, setSortBy] = useState<'createdAt_ASC' | 'createdAt_DESC'>( + 'createdAt_DESC', + ); + + const [modalState, setModalState] = useState<{ + [key in ModalState]: boolean; + }>({ + [ModalState.SAME]: false, + [ModalState.DELETE]: false, + }); + const [fundModalMode, setFundModalMode] = useState<'edit' | 'create'>( + 'create', + ); + + const openModal = (modal: ModalState): void => + setModalState((prevState) => ({ ...prevState, [modal]: true })); + + const closeModal = (modal: ModalState): void => + setModalState((prevState) => ({ ...prevState, [modal]: false })); + + const handleOpenModal = useCallback( + (fund: InterfaceFundInfo | null, mode: 'edit' | 'create'): void => { + setFund(fund); + setFundModalMode(mode); + openModal(ModalState.SAME); + }, + [openModal], + ); + + const { + data: fundData, + loading: fundLoading, + error: fundError, + refetch: refetchFunds, + }: { + data?: { + fundsByOrganization: InterfaceFundInfo[]; + }; + loading: boolean; + error?: Error | undefined; + refetch: () => void; + } = useQuery(FUND_LIST, { + variables: { + organizationId: orgId, + filter: searchTerm, + orderBy: sortBy, + }, + }); + + const handleDeleteClick = useCallback( + (fund: InterfaceFundInfo): void => { + setFund(fund); + openModal(ModalState.DELETE); + }, + [openModal], + ); + + const funds = useMemo(() => fundData?.fundsByOrganization ?? [], [fundData]); + + const handleClick = (fundId: string): void => { + navigate(`/orgfundcampaign/${orgId}/${fundId}`); + }; + + if (fundLoading) { + return ; + } + if (fundError) { + return ( +
    +
    + +
    + Error occured while loading Funds +
    + {fundError.message} +
    +
    +
    + ); + } + + const columns: GridColDef[] = [ + { + field: 'id', + headerName: 'Sr. No.', + flex: 1, + minWidth: 100, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return
    {params.row.id}
    ; + }, + }, + { + field: 'fundName', + headerName: 'Fund Name', + flex: 2, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( +
    handleClick(params.row._id as string)} + > + {params.row.name} +
    + ); + }, + }, + { + field: 'createdBy', + headerName: 'Created By', + flex: 2, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return params.row.creator.firstName + ' ' + params.row.creator.lastName; + }, + }, + { + field: 'createdOn', + headerName: 'Created On', + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + flex: 2, + renderCell: (params: GridCellParams) => { + return ( +
    + {dayjs(params.row.createdAt).format('DD/MM/YYYY')} +
    + ); + }, + }, + { + field: 'status', + headerName: 'Status', + flex: 2, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return params.row.isArchived ? 'Archived' : 'Active'; + }, + }, + { + field: 'action', + headerName: 'Action', + flex: 2, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( + <> + + + + ); + }, + }, + { + field: 'assocCampaigns', + headerName: 'Associated Campaigns', + flex: 2, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( + + ); + }, + }, + ]; + + return ( +
    +
    +
    + setSearchTerm(e.target.value)} + data-testid="searchByName" + /> + +
    +
    +
    + + + + {tCommon('sort')} + + + setSortBy('createdAt_DESC')} + data-testid="createdAt_DESC" + > + {t('createdLatest')} + + setSortBy('createdAt_ASC')} + data-testid="createdAt_ASC" + > + {t('createdEarliest')} + + + +
    +
    + +
    +
    +
    + + row._id} + slots={{ + noRowsOverlay: () => ( + + {t('noFundsFound')} + + ), + }} + sx={dataGridStyle} + getRowClassName={() => `${styles.rowBackground}`} + autoHeight + rowHeight={65} + rows={funds.map((fund, index) => ({ + id: index + 1, + ...fund, + }))} + columns={columns} + isRowSelectable={() => false} + /> + closeModal(ModalState.SAME)} + refetchFunds={refetchFunds} + fund={fund} + orgId={orgId} + mode={fundModalMode} + /> + + closeModal(ModalState.DELETE)} + fund={fund} + refetchFunds={refetchFunds} + /> +
    + ); +}; + +export default organizationFunds; diff --git a/src/screens/OrganizationFunds/OrganizationFundsMocks.ts b/src/screens/OrganizationFunds/OrganizationFundsMocks.ts new file mode 100644 index 0000000000..cd03dc7f31 --- /dev/null +++ b/src/screens/OrganizationFunds/OrganizationFundsMocks.ts @@ -0,0 +1,256 @@ +import { + CREATE_FUND_MUTATION, + REMOVE_FUND_MUTATION, + UPDATE_FUND_MUTATION, +} from 'GraphQl/Mutations/FundMutation'; +import { FUND_LIST } from 'GraphQl/Queries/fundQueries'; + +export const MOCKS = [ + { + request: { + query: FUND_LIST, + variables: { + organizationId: 'orgId', + orderBy: 'createdAt_DESC', + filter: '', + }, + }, + result: { + data: { + fundsByOrganization: [ + { + _id: 'fundId', + name: 'Fund 1', + refrenceNumber: '1111', + taxDeductible: true, + isArchived: false, + isDefault: false, + createdAt: '2024-06-22', + organizationId: 'orgId', + creator: { + _id: 'creatorId1', + firstName: 'John', + lastName: 'Doe', + }, + }, + { + _id: 'fundId2', + name: 'Fund 2', + refrenceNumber: '2222', + taxDeductible: true, + isArchived: true, + isDefault: false, + createdAt: '2024-06-21', + organizationId: 'orgId', + creator: { + _id: 'creatorId1', + firstName: 'John', + lastName: 'Doe', + }, + }, + ], + }, + }, + }, + { + request: { + query: FUND_LIST, + variables: { + organizationId: 'orgId', + orderBy: 'createdAt_ASC', + filter: '', + }, + }, + result: { + data: { + fundsByOrganization: [ + { + _id: 'fundId', + name: 'Fund 2', + refrenceNumber: '2222', + taxDeductible: true, + isArchived: true, + isDefault: false, + createdAt: '2024-06-21', + organizationId: 'orgId', + creator: { + _id: 'creatorId1', + firstName: 'John', + lastName: 'Doe', + }, + }, + { + _id: 'fundId2', + name: 'Fund 1', + refrenceNumber: '1111', + taxDeductible: true, + isArchived: false, + isDefault: false, + createdAt: '2024-06-22', + organizationId: 'orgId', + creator: { + _id: 'creatorId1', + firstName: 'John', + lastName: 'Doe', + }, + }, + ], + }, + }, + }, + { + request: { + query: FUND_LIST, + variables: { + organizationId: 'orgId', + orderBy: 'createdAt_DESC', + filter: '2', + }, + }, + result: { + data: { + fundsByOrganization: [ + { + _id: 'fundId', + name: 'Fund 2', + refrenceNumber: '2222', + taxDeductible: true, + isArchived: true, + isDefault: false, + createdAt: '2024-06-21', + organizationId: 'orgId', + creator: { + _id: 'creatorId1', + firstName: 'John', + lastName: 'Doe', + }, + }, + ], + }, + }, + }, + { + request: { + query: CREATE_FUND_MUTATION, + variables: { + name: 'Fund 2', + refrenceNumber: '2222', + taxDeductible: false, + isArchived: false, + isDefault: true, + organizationId: 'orgId', + }, + }, + result: { + data: { + createFund: { + _id: '2222', + }, + }, + }, + }, + { + request: { + query: UPDATE_FUND_MUTATION, + variables: { + id: 'fundId', + name: 'Fund 2', + refrenceNumber: '2222', + taxDeductible: false, + isArchived: true, + isDefault: true, + }, + }, + result: { + data: { + updateFund: { + _id: 'fundId', + }, + }, + }, + }, + { + request: { + query: REMOVE_FUND_MUTATION, + variables: { + id: 'fundId', + }, + }, + result: { + data: { + removeFund: { + _id: 'fundId', + }, + }, + }, + }, +]; + +export const NO_FUNDS = [ + { + request: { + query: FUND_LIST, + variables: { + organizationId: 'orgId', + orderBy: 'createdAt_DESC', + filter: '', + }, + }, + result: { + data: { + fundsByOrganization: [], + }, + }, + }, +]; + +export const MOCKS_ERROR = [ + { + request: { + query: FUND_LIST, + variables: { + organizationId: 'orgId', + orderBy: 'createdAt_DESC', + filter: '', + }, + }, + error: new Error('Mock graphql error'), + }, + { + request: { + query: CREATE_FUND_MUTATION, + variables: { + name: 'Fund 2', + refrenceNumber: '2222', + taxDeductible: false, + isArchived: false, + isDefault: true, + organizationId: 'orgId', + }, + }, + error: new Error('Mock graphql error'), + }, + { + request: { + query: REMOVE_FUND_MUTATION, + variables: { + id: 'fundId', + }, + }, + error: new Error('Mock graphql error'), + }, + { + request: { + query: UPDATE_FUND_MUTATION, + variables: { + id: 'fundId', + name: 'Fund 2', + refrenceNumber: '2222', + taxDeductible: false, + isArchived: true, + isDefault: true, + }, + }, + error: new Error('Mock graphql error'), + }, +]; diff --git a/src/screens/OrganizationPeople/AddMember.tsx b/src/screens/OrganizationPeople/AddMember.tsx new file mode 100644 index 0000000000..9737ef5c50 --- /dev/null +++ b/src/screens/OrganizationPeople/AddMember.tsx @@ -0,0 +1,564 @@ +import { useLazyQuery, useMutation, useQuery } from '@apollo/client'; +import { Search } from '@mui/icons-material'; +import EmailOutlinedIcon from '@mui/icons-material/EmailOutlined'; +import Paper from '@mui/material/Paper'; +import Table from '@mui/material/Table'; +import TableBody from '@mui/material/TableBody'; +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 { + ADD_MEMBER_MUTATION, + SIGNUP_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import { + ORGANIZATIONS_LIST, + ORGANIZATIONS_MEMBER_CONNECTION_LIST, + USERS_CONNECTION_LIST, +} from 'GraphQl/Queries/Queries'; +import Loader from 'components/Loader/Loader'; +import type { ChangeEvent } from 'react'; +import React, { useEffect, useState } from 'react'; +import { Button, Dropdown, Form, InputGroup, Modal } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; +import { Link, useParams } from 'react-router-dom'; +import { toast } from 'react-toastify'; +import { errorHandler } from 'utils/errorHandler'; +import type { + InterfaceQueryOrganizationsListObject, + InterfaceQueryUserListItem, +} from 'utils/interfaces'; +import styles from './OrganizationPeople.module.css'; + +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, + }, +})); + +function AddMember(): JSX.Element { + const { t: translateOrgPeople } = useTranslation('translation', { + keyPrefix: 'organizationPeople', + }); + + const { t: translateAddMember } = useTranslation('translation', { + keyPrefix: 'addMember', + }); + + const { t: tCommon } = useTranslation('common'); + + document.title = translateOrgPeople('title'); + + const [addUserModalisOpen, setAddUserModalIsOpen] = useState(false); + + function openAddUserModal(): void { + setAddUserModalIsOpen(true); + } + + const toggleDialogModal = /* istanbul ignore next */ (): void => + setAddUserModalIsOpen(!addUserModalisOpen); + + const [createNewUserModalisOpen, setCreateNewUserModalIsOpen] = + useState(false); + function openCreateNewUserModal(): void { + setCreateNewUserModalIsOpen(true); + } + + function closeCreateNewUserModal(): void { + setCreateNewUserModalIsOpen(false); + } + const toggleCreateNewUserModal = /* istanbul ignore next */ (): void => + setCreateNewUserModalIsOpen(!addUserModalisOpen); + + const [addMember] = useMutation(ADD_MEMBER_MUTATION); + + const createMember = async (userId: string): Promise => { + try { + await addMember({ + variables: { + userid: userId, + orgid: currentUrl, + }, + }); + toast.success(tCommon('addedSuccessfully', { item: 'Member' })); + memberRefetch({ + orgId: currentUrl, + }); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + console.log(error.message); + } + } + }; + + const { orgId: currentUrl } = useParams(); + + const [showPassword, setShowPassword] = useState(false); + const [showConfirmPassword, setShowConfirmPassword] = + useState(false); + + const togglePassword = (): void => setShowPassword(!showPassword); + const toggleConfirmPassword = (): void => + setShowConfirmPassword(!showConfirmPassword); + + const [userName, setUserName] = useState(''); + + const { + data: organizationData, + }: { + data?: { + organizations: InterfaceQueryOrganizationsListObject[]; + }; + } = useQuery(ORGANIZATIONS_LIST, { + variables: { id: currentUrl }, + }); + + const getMembersId = (): string[] => { + if (memberData) { + const ids = memberData?.organizationsMemberConnection.edges.map( + (member: { _id: string }) => member._id, + ); + return ids; + } + return []; + }; + + const { data: memberData, refetch: memberRefetch } = useLazyQuery( + ORGANIZATIONS_MEMBER_CONNECTION_LIST, + { + variables: { + firstName_contains: '', + lastName_contains: '', + orgId: currentUrl, + }, + }, + )[1]; + + const { + data: allUsersData, + loading: allUsersLoading, + refetch: allUsersRefetch, + } = useQuery(USERS_CONNECTION_LIST, { + variables: { + id_not_in: getMembersId(), + firstName_contains: '', + lastName_contains: '', + }, + }); + + useEffect(() => { + memberRefetch({ + orgId: currentUrl, + }); + }); + + const [registerMutation] = useMutation(SIGNUP_MUTATION); + + const [createUserVariables, setCreateUserVariables] = React.useState({ + firstName: '', + lastName: '', + email: '', + password: '', + confirmPassword: '', + }); + + const handleCreateUser = async (): Promise => { + if ( + !( + createUserVariables.email && + createUserVariables.password && + createUserVariables.firstName && + createUserVariables.lastName + ) + ) { + toast.error(translateOrgPeople('invalidDetailsMessage')); + } else if ( + createUserVariables.password !== createUserVariables.confirmPassword + ) { + toast.error(translateOrgPeople('passwordNotMatch')); + } else { + try { + const registeredUser = await registerMutation({ + variables: { + firstName: createUserVariables.firstName, + lastName: createUserVariables.lastName, + email: createUserVariables.email, + password: createUserVariables.password, + orgId: currentUrl, + }, + }); + const createdUserId = registeredUser?.data.signUp.user._id; + + await createMember(createdUserId); + + closeCreateNewUserModal(); + + /* istanbul ignore next */ + setCreateUserVariables({ + firstName: '', + lastName: '', + email: '', + password: '', + confirmPassword: '', + }); + } catch (error: unknown) { + /* istanbul ignore next */ + errorHandler(translateOrgPeople, error); + } + } + }; + + /* istanbul ignore next */ + const handleFirstName = (e: ChangeEvent): void => { + const firstName = e.target.value; + + setCreateUserVariables({ ...createUserVariables, firstName }); + }; + + /* istanbul ignore next */ + const handleLastName = (e: ChangeEvent): void => { + const lastName = e.target.value; + + setCreateUserVariables({ ...createUserVariables, lastName }); + }; + + /* istanbul ignore next */ + const handleEmailChange = (e: ChangeEvent): void => { + const email = e.target.value; + + setCreateUserVariables({ ...createUserVariables, email }); + }; + + /* istanbul ignore next */ + const handlePasswordChange = (e: ChangeEvent): void => { + const password = e.target.value; + + setCreateUserVariables({ ...createUserVariables, password }); + }; + + /* istanbul ignore next */ + const handleConfirmPasswordChange = ( + e: ChangeEvent, + ): void => { + const confirmPassword = e.target.value; + + setCreateUserVariables({ ...createUserVariables, confirmPassword }); + }; + + const handleUserModalSearchChange = (e: React.FormEvent): void => { + e.preventDefault(); + /* istanbul ignore next */ + const [firstName, lastName] = userName.split(' '); + + const newFilterData = { + firstName_contains: firstName || '', + lastName_contains: lastName || '', + }; + + allUsersRefetch({ + ...newFilterData, + }); + }; + + return ( + <> + + + {translateOrgPeople('addMembers')} + + + { + openAddUserModal(); + }} + > + + {translateOrgPeople('existingUser')} + + + { + openCreateNewUserModal(); + }} + > + + + + + + + + {translateOrgPeople('addMembers')} + + + {allUsersLoading ? ( + <> + + + ) : ( + <> +
    +
    + { + const { value } = e.target; + setUserName(value); + }} + /> + + +
    + + + + + # + + {translateAddMember('user')} + + + {translateAddMember('addMember')} + + + + + {allUsersData && + allUsersData.users.length > 0 && + allUsersData.users.map( + ( + userDetails: InterfaceQueryUserListItem, + index: number, + ) => ( + + + {index + 1} + + + + {userDetails.user.firstName + + ' ' + + userDetails.user.lastName} +
    + {userDetails.user.email} + +
    + + + +
    + ), + )} +
    +
    +
    + + )} +
    +
    + + + + Create User + + +
    +
    +
    +
    {translateOrgPeople('firstName')}
    + + + +
    +
    +
    {translateOrgPeople('lastName')}
    + + + +
    +
    +
    {translateOrgPeople('emailAddress')}
    + + + + + + +
    {translateOrgPeople('password')}
    + + + + {showPassword ? ( + + ) : ( + + )} + + +
    {translateOrgPeople('confirmPassword')}
    + + + + {showConfirmPassword ? ( + + ) : ( + + )} + + +
    {translateOrgPeople('organization')}
    + + + +
    +
    + + +
    +
    +
    + + ); +} + +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/MockDataTypes.ts b/src/screens/OrganizationPeople/MockDataTypes.ts new file mode 100644 index 0000000000..c12bb05531 --- /dev/null +++ b/src/screens/OrganizationPeople/MockDataTypes.ts @@ -0,0 +1,77 @@ +import type { DocumentNode } from 'graphql'; +import type { InterfaceQueryOrganizationsListObject } from 'utils/interfaces'; +type User = { + __typename: string; + firstName: string; + lastName: string; + image: string | null; + _id: string; + email: string; + createdAt: string; + joinedOrganizations: { + __typename: string; + _id: string; + name?: string; + creator?: { + _id: string; + firstName: string; + lastName: string; + email: string; + image: null; + createdAt: string; + }; + }[]; +}; +type Edge = { + _id?: string; + firstName?: string; + lastName?: string; + image?: string | null; + email?: string; + createdAt?: string; + user?: Edge; +}; +export type TestMock = { + request: { + query: DocumentNode; + variables: { + id?: string; + orgId?: string; + orgid?: string; + firstNameContains?: string; + lastNameContains?: string; + firstName_contains?: string; + lastName_contains?: string; + id_not_in?: string[]; + userid?: string; + firstName?: string; + lastName?: string; + email?: string; + password?: string; + }; + }; + result: { + __typename?: string; + data: { + __typename?: string; + createMember?: { + __typename: string; + _id: string; + }; + signUp?: { + user?: { + _id: string; + }; + accessToken?: string; + refreshToken?: string; + }; + users?: { user?: User }[]; + organizations?: InterfaceQueryOrganizationsListObject[]; + organizationsMemberConnection?: { + edges?: Edge[]; + user?: Edge[]; + }; + }; + }; + newData?: () => TestMock['result']; +}; diff --git a/src/screens/OrganizationPeople/OrganizationPeople.module.css b/src/screens/OrganizationPeople/OrganizationPeople.module.css new file mode 100644 index 0000000000..5ff4b0d297 --- /dev/null +++ b/src/screens/OrganizationPeople/OrganizationPeople.module.css @@ -0,0 +1,121 @@ +@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.test.tsx new file mode 100644 index 0000000000..8ea7b30219 --- /dev/null +++ b/src/screens/OrganizationPeople/OrganizationPeople.test.tsx @@ -0,0 +1,1355 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { act, fireEvent, render, screen } from '@testing-library/react'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import userEvent from '@testing-library/user-event'; +import { I18nextProvider } from 'react-i18next'; +import OrganizationPeople from './OrganizationPeople'; +import { store } from 'state/store'; +import { + ORGANIZATIONS_LIST, + ORGANIZATIONS_MEMBER_CONNECTION_LIST, + USERS_CONNECTION_LIST, + USER_LIST_FOR_TABLE, +} from 'GraphQl/Queries/Queries'; +import 'jest-location-mock'; +import i18nForTest from 'utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { + ADD_MEMBER_MUTATION, + SIGNUP_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import type { TestMock } from './MockDataTypes'; + +const createMemberMock = ( + orgId = '', + firstNameContains = '', + lastNameContains = '', +): TestMock => ({ + request: { + query: ORGANIZATIONS_MEMBER_CONNECTION_LIST, + variables: { + orgId: orgId, + firstNameContains, + lastNameContains, + }, + }, + result: { + data: { + organizationsMemberConnection: { + edges: [ + { + _id: '64001660a711c62d5b4076a2', + firstName: 'Aditya', + lastName: 'Memberguy', + image: null, + email: 'member@gmail.com', + createdAt: '2023-03-02T03:22:08.101Z', + }, + ], + }, + }, + }, + newData: () => ({ + data: { + organizationsMemberConnection: { + edges: [ + { + user: { + __typename: 'User', + _id: '64001660a711c62d5b4076a2', + firstName: 'Aditya', + lastName: 'Memberguy', + image: null, + email: 'member@gmail.com', + createdAt: '2023-03-02T03:22:08.101Z', + }, + }, + ], + }, + }, + }), +}); + +const createAdminMock = ( + orgId = '', + firstNameContains = '', + lastNameContains = '', +): TestMock => ({ + request: { + query: ORGANIZATIONS_MEMBER_CONNECTION_LIST, + variables: { + orgId, + firstNameContains, + lastNameContains, + }, + }, + result: { + data: { + organizationsMemberConnection: { + edges: [ + { + user: { + _id: '64001660a711c62d5b4076a2', + firstName: 'Aditya', + lastName: 'Adminguy', + image: null, + email: 'admin@gmail.com', + createdAt: '2023-03-02T03:22:08.101Z', + }, + }, + ], + }, + }, + }, + newData: () => ({ + data: { + organizationsMemberConnection: { + __typename: 'UserConnection', + edges: [ + { + user: { + __typename: 'User', + _id: '64001660a711c62d5b4076a2', + firstName: 'Aditya', + lastName: 'Adminguy', + image: null, + email: 'admin@gmail.com', + createdAt: '2023-03-02T03:22:08.101Z', + lol: true, + }, + }, + ], + }, + }, + }), +}); + +const createUserMock = ( + firstNameContains = '', + lastNameContains = '', +): TestMock => ({ + request: { + query: USER_LIST_FOR_TABLE, + variables: { + firstNameContains, + lastNameContains, + }, + }, + result: { + data: { + users: [ + { + user: { + __typename: 'User', + firstName: 'Aditya', + lastName: 'Userguy', + image: 'tempUrl', + _id: '64001660a711c62d5b4076a2', + email: 'adidacreator1@gmail.com', + createdAt: '2023-03-02T03:22:08.101Z', + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af1', + }, + ], + }, + }, + { + user: { + __typename: 'User', + firstName: 'Aditya', + lastName: 'Userguytwo', + image: 'tempUrl', + _id: '6402030dce8e8406b8f07b0e', + email: 'adi1@gmail.com', + createdAt: '2023-03-03T14:24:13.084Z', + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + }, + ], + }, + }, + ], + }, + }, +}); + +const MOCKS: TestMock[] = [ + { + request: { + query: ORGANIZATIONS_LIST, + variables: { + id: 'orgid', + }, + }, + result: { + data: { + organizations: [ + { + _id: 'orgid', + image: '', + creator: { + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + name: 'name', + description: 'description', + userRegistrationRequired: false, + visibleInSearch: false, + address: { + city: 'string', + countryCode: 'string', + dependentLocality: 'string', + line1: 'string', + line2: 'string', + postalCode: 'string', + sortingCode: 'string', + state: 'string', + }, + members: [ + { + _id: 'id', + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + ], + admins: [ + { + _id: 'id', + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + createdAt: '12-03-2024', + }, + ], + membershipRequests: [ + { + _id: 'id', + user: { + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + }, + ], + blockedUsers: [ + { + _id: 'id', + firstName: 'firstName', + lastName: 'lastName', + email: 'email', + }, + ], + }, + ], + }, + }, + }, + + { + //These are mocks for 1st query (member list) + request: { + query: ORGANIZATIONS_MEMBER_CONNECTION_LIST, + variables: { + orgId: 'orgid', + firstName_contains: '', + lastName_contains: '', + }, + }, + result: { + data: { + organizationsMemberConnection: { + edges: [ + { + _id: '64001660a711c62d5b4076a2', + firstName: 'Aditya', + lastName: 'Memberguy', + image: null, + email: 'member@gmail.com', + createdAt: '2023-03-02T03:22:08.101Z', + }, + ], + }, + }, + }, + newData: () => ({ + //A function if multiple request are sent + data: { + organizationsMemberConnection: { + edges: [ + { + _id: '64001660a711c62d5b4076a2', + firstName: 'Aditya', + lastName: 'Memberguy', + image: null, + email: 'member@gmail.com', + createdAt: '2023-03-02T03:22:08.101Z', + }, + ], + }, + }, + }), + }, + + { + request: { + query: ORGANIZATIONS_MEMBER_CONNECTION_LIST, + variables: { + orgId: 'orgid', + firstName_contains: '', + lastName_contains: '', + }, + }, + result: { + data: { + organizationsMemberConnection: { + edges: [ + { + _id: '64001660a711c62d5b4076a2', + firstName: 'Aditya', + lastName: 'Adminguy', + image: null, + email: 'admin@gmail.com', + createdAt: '2023-03-02T03:22:08.101Z', + }, + ], + }, + }, + }, + newData: () => ({ + data: { + organizationsMemberConnection: { + __typename: 'UserConnection', + edges: [ + { + __typename: 'User', + _id: '64001660a711c62d5b4076a2', + firstName: 'Aditya', + lastName: 'Adminguy', + image: null, + email: 'admin@gmail.com', + createdAt: '2023-03-02T03:22:08.101Z', + lol: true, + }, + ], + }, + }, + }), + }, + + { + //This is mock for user list + request: { + query: USER_LIST_FOR_TABLE, + variables: { + firstName_contains: '', + lastName_contains: '', + }, + }, + result: { + data: { + users: [ + { + user: { + __typename: 'User', + firstName: 'Aditya', + lastName: 'Userguy', + image: 'tempUrl', + _id: '64001660a711c62d5b4076a2', + email: 'adidacreator1@gmail.com', + createdAt: '2023-03-02T03:22:08.101Z', + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af1', + }, + ], + }, + }, + { + user: { + __typename: 'User', + firstName: 'Aditya', + lastName: 'Userguytwo', + image: 'tempUrl', + _id: '6402030dce8e8406b8f07b0e', + email: 'adi1@gmail.com', + createdAt: '2023-03-03T14:24:13.084Z', + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + }, + ], + }, + }, + ], + }, + }, + }, + + createMemberMock('orgid', 'Aditya', ''), + createMemberMock('orgid', '', 'Memberguy'), + createMemberMock('orgid', 'Aditya', 'Memberguy'), + + createAdminMock('orgid', 'Aditya', ''), + createAdminMock('orgid', '', 'Adminguy'), + createAdminMock('orgid', 'Aditya', 'Adminguy'), + + createUserMock('Aditya', ''), + createUserMock('', 'Userguytwo'), + createUserMock('Aditya', 'Userguytwo'), + + { + request: { + query: USERS_CONNECTION_LIST, + variables: { + id_not_in: ['64001660a711c62d5b4076a2'], + firstName_contains: '', + lastName_contains: '', + }, + }, + result: { + data: { + users: [ + { + user: { + firstName: 'Vyvyan', + lastName: 'Kerry', + image: null, + _id: '65378abd85008f171cf2990d', + email: 'testadmin1@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + joinedOrganizations: [ + { + _id: '6537904485008f171cf29924', + name: 'Unity Foundation', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + }, + __typename: 'Organization', + }, + ], + __typename: 'User', + }, + }, + ], + }, + }, + }, + { + request: { + query: SIGNUP_MUTATION, + variables: { + firstName: 'Disha', + lastName: 'Talreja', + email: 'test@gmail.com', + password: 'dishatalreja', + orgId: 'orgId', + }, + }, + result: { + data: { + signUp: { + user: { + _id: '', + }, + accessToken: 'accessToken', + refreshToken: 'refreshToken', + }, + }, + }, + }, + { + request: { + query: ADD_MEMBER_MUTATION, + variables: { + userid: '65378abd85008f171cf2990d', + orgid: 'orgid', + }, + }, + result: { + data: { + createMember: { + _id: '6437904485008f171cf29924', + __typename: 'Organization', + }, + }, + }, + }, +]; + +const EMPTYMOCKS: TestMock[] = [ + { + request: { + query: ORGANIZATIONS_LIST, + variables: { + id: 'orgid', + }, + }, + result: { + data: { + organizations: [], + }, + }, + }, + + { + //These are mocks for 1st query (member list) + request: { + query: ORGANIZATIONS_MEMBER_CONNECTION_LIST, + variables: { + orgId: 'orgid', + firstName_contains: '', + lastName_contains: '', + }, + }, + result: { + data: { + organizationsMemberConnection: { + edges: [], + }, + }, + }, + }, + + { + request: { + query: ORGANIZATIONS_MEMBER_CONNECTION_LIST, + variables: { + orgId: 'orgid', + firstName_contains: '', + lastName_contains: '', + }, + }, + result: { + data: { + organizationsMemberConnection: { + edges: [], + }, + }, + }, + }, + + { + //This is mock for user list + request: { + query: USER_LIST_FOR_TABLE, + variables: { + firstName_contains: '', + lastName_contains: '', + }, + }, + result: { + data: { + users: [], + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(EMPTYMOCKS, true); +async function wait(ms = 2): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} +const linkURL = 'orgid'; +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ 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(); + +describe('Organization People Page', () => { + const searchData = { + fullNameMember: 'Aditya Memberguy', + fullNameAdmin: 'Aditya Adminguy', + fullNameUser: 'Aditya Userguytwo', + location: 'Delhi, India', + event: 'Event', + }; + + test('Correct mock data should be queried', async () => { + window.location.assign('/orgpeople/orgid'); + + const dataQuery1 = + MOCKS[1]?.result?.data?.organizationsMemberConnection?.edges; + expect(dataQuery1).toEqual([ + { + _id: '64001660a711c62d5b4076a2', + firstName: 'Aditya', + lastName: 'Memberguy', + image: null, + email: 'member@gmail.com', + createdAt: '2023-03-02T03:22:08.101Z', + }, + ]); + + const dataQuery2 = + MOCKS[2]?.result?.data?.organizationsMemberConnection?.edges; + + const dataQuery3 = MOCKS[3]?.result?.data?.users; + + expect(dataQuery3).toEqual([ + { + user: { + __typename: 'User', + firstName: 'Aditya', + lastName: 'Userguy', + image: 'tempUrl', + _id: '64001660a711c62d5b4076a2', + email: 'adidacreator1@gmail.com', + createdAt: '2023-03-02T03:22:08.101Z', + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af1', + }, + ], + }, + }, + { + user: { + __typename: 'User', + firstName: 'Aditya', + lastName: 'Userguytwo', + image: 'tempUrl', + _id: '6402030dce8e8406b8f07b0e', + email: 'adi1@gmail.com', + createdAt: '2023-03-03T14:24:13.084Z', + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + }, + ], + }, + }, + ]); + + expect(dataQuery2).toEqual([ + { + _id: '64001660a711c62d5b4076a2', + firstName: 'Aditya', + lastName: 'Adminguy', + image: null, + email: 'admin@gmail.com', + createdAt: '2023-03-02T03:22:08.101Z', + }, + ]); + + expect(window.location).toBeAt('/orgpeople/orgid'); + }); + + test('It is necessary to query the correct mock data.', async () => { + window.location.assign('/orgpeople/orgid'); + + const { container } = render( + + + + + + + + + , + ); + + expect(container.textContent).not.toBe('Loading data...'); + + await wait(); + + expect(window.location).toBeAt('/orgpeople/orgid'); + }); + + test('Testing MEMBERS list', async () => { + window.location.assign('/orgpeople/orgid'); + render( + + + + + + + + + , + ); + await wait(); + const dropdownToggles = screen.getAllByTestId('role'); + + dropdownToggles.forEach((dropdownToggle) => { + userEvent.click(dropdownToggle); + }); + + const memebersDropdownItem = screen.getByTestId('members'); + userEvent.click(memebersDropdownItem); + await wait(); + + const findtext = screen.getByText(/Aditya Memberguy/i); + await wait(); + expect(findtext).toBeInTheDocument(); + + userEvent.type( + screen.getByPlaceholderText(/Enter Full Name/i), + searchData.fullNameMember, + ); + await wait(); + expect(screen.getByPlaceholderText(/Enter Full Name/i)).toHaveValue( + searchData.fullNameMember, + ); + + await wait(); + expect(window.location).toBeAt('/orgpeople/orgid'); + }); + + test('Testing MEMBERS list with filters', async () => { + window.location.assign('/orgpeople/orgid'); + render( + + + + + + + + + , + ); + await wait(); + + const fullNameInput = screen.getByPlaceholderText(/Enter Full Name/i); + + // Only First Name + userEvent.type(fullNameInput, searchData.fullNameMember); + await wait(); + + let findtext = screen.getByText(/Aditya Memberguy/i); + await wait(); + expect(findtext).toBeInTheDocument(); + + findtext = screen.getByText(/Aditya Memberguy/i); + await wait(); + expect(findtext).toBeInTheDocument(); + await wait(); + expect(window.location).toBeAt('/orgpeople/orgid'); + }); + + test('Testing ADMIN LIST', async () => { + window.location.assign('/orgpeople/orgid'); + + render( + + + + + + + + + , + ); + + await wait(); + + // Get all dropdown toggles by test id + const dropdownToggles = screen.getAllByTestId('role'); + + // Click the dropdown toggle to open the dropdown menu + dropdownToggles.forEach((dropdownToggle) => { + userEvent.click(dropdownToggle); + }); + + // Click the "Admin" dropdown item + const adminDropdownItem = screen.getByTestId('admins'); + userEvent.click(adminDropdownItem); + + // Wait for any asynchronous operations to complete + await wait(); + // remove this comment when table fecthing functionality is fixed + // Assert that the "Aditya Adminguy" text is present + // const findtext = screen.getByText('Aditya Adminguy'); + // expect(findtext).toBeInTheDocument(); + + // Type in the full name input field + userEvent.type( + screen.getByPlaceholderText(/Enter Full Name/i), + searchData.fullNameAdmin, + ); + + // Wait for any asynchronous operations to complete + await wait(); + + // Assert the value of the full name input field + expect(screen.getByPlaceholderText(/Enter Full Name/i)).toHaveValue( + searchData.fullNameAdmin, + ); + await wait(); + + // Wait for any asynchronous operations to complete + await wait(); + expect(window.location).toBeAt('/orgpeople/orgid'); + }); + + test('Testing ADMIN list with filters', async () => { + window.location.assign('/orgpeople/orgid'); + render( + + + + + + + + + , + ); + + // Wait for the component to finish rendering + await wait(); + + // Click on the dropdown toggle to open the menu + userEvent.click(screen.getByTestId('role')); + await wait(); + + // Click on the "Admins" option in the dropdown menu + userEvent.click(screen.getByTestId('admins')); + await wait(); + + // Type the full name into the input field + const fullNameInput = screen.getByPlaceholderText(/Enter Full Name/i); + userEvent.type(fullNameInput, searchData.fullNameAdmin); + + // Wait for the results to update + await wait(); + const btn = screen.getByTestId('searchbtn'); + userEvent.click(btn); + // remove this comment when table fecthing functionality is fixed + // Check if the expected name is present in the results + // let findtext = screen.getByText(/Aditya Adminguy/i); + // expect(findtext).toBeInTheDocument(); + + // Ensure that the name is still present after filtering + await wait(); + expect(window.location).toBeAt('/orgpeople/orgid'); + }); + + test('Testing add existing user modal', async () => { + window.location.assign('/orgpeople/6401ff65ce8e8406b8f07af1'); + render( + + + + + + + + + , + ); + + // Wait for the component to finish rendering + await wait(); + + // Click on the dropdown toggle to open the menu + userEvent.click(screen.getByTestId('addMembers')); + await wait(); + + expect(screen.getByTestId('existingUser')).toBeInTheDocument(); + + // Click on the "Admins" option in the dropdown menu + userEvent.click(screen.getByTestId('existingUser')); + await wait(); + + expect(screen.getByTestId('addExistingUserModal')).toBeInTheDocument(); + await wait(); + + userEvent.click(screen.getByTestId('addBtn')); + }); + + test('Open and search existing user', async () => { + window.location.assign('/orgpeople/orgid'); + render( + + + + + + + + + , + ); + + // Wait for the component to finish rendering + await wait(); + + // Click on the dropdown toggle to open the menu + userEvent.click(screen.getByTestId('addMembers')); + await wait(); + + // Click on the "Admins" option in the dropdown menu + userEvent.click(screen.getByTestId('existingUser')); + await wait(); + + expect(screen.getByTestId('addExistingUserModal')).toBeInTheDocument(); + + fireEvent.change(screen.getByTestId('searchUser'), { + target: { value: 'Disha' }, + }); + }); + + test('Open and close add new user modal', async () => { + window.location.assign('/orgpeople/orgid'); + render( + + + + + + + + + , + ); + + // Wait for the component to finish rendering + await wait(); + + // Click on the dropdown toggle to open the menu + userEvent.click(screen.getByTestId('addMembers')); + await wait(); + + // Click on the "Admins" option in the dropdown menu + userEvent.click(screen.getByTestId('newUser')); + await wait(); + + expect(screen.getByTestId('addNewUserModal')).toBeInTheDocument(); + + userEvent.click(screen.getByTestId('closeBtn')); + }); + + test('Testing add new user modal', async () => { + window.location.assign('/orgpeople/orgid'); + render( + + + + + + + + + , + ); + + // Wait for the component to finish rendering + await wait(); + + // Click on the dropdown toggle to open the menu + userEvent.click(screen.getByTestId('addMembers')); + await wait(); + + // Click on the "Admins" option in the dropdown menu + userEvent.click(screen.getByTestId('newUser')); + await wait(); + + expect(screen.getByTestId('addNewUserModal')).toBeInTheDocument(); + + fireEvent.change(screen.getByTestId('firstNameInput'), { + target: { value: 'Disha' }, + }); + expect(screen.getByTestId('firstNameInput')).toHaveValue('Disha'); + + fireEvent.change(screen.getByTestId('lastNameInput'), { + target: { value: 'Talreja' }, + }); + expect(screen.getByTestId('lastNameInput')).toHaveValue('Talreja'); + + fireEvent.change(screen.getByTestId('emailInput'), { + target: { value: 'test@gmail.com' }, + }); + expect(screen.getByTestId('emailInput')).toHaveValue('test@gmail.com'); + + fireEvent.change(screen.getByTestId('passwordInput'), { + target: { value: 'dishatalreja' }, + }); + userEvent.click(screen.getByTestId('showPassword')); + expect(screen.getByTestId('passwordInput')).toHaveValue('dishatalreja'); + + fireEvent.change(screen.getByTestId('confirmPasswordInput'), { + target: { value: 'dishatalreja' }, + }); + userEvent.click(screen.getByTestId('showConfirmPassword')); + expect(screen.getByTestId('confirmPasswordInput')).toHaveValue( + 'dishatalreja', + ); + + userEvent.click(screen.getByTestId('createBtn')); + }); + + test('Throw invalid details error in add new user modal', async () => { + window.location.assign('/orgpeople/orgid'); + render( + + + + + + + + + , + ); + + // Wait for the component to finish rendering + await wait(); + + // Click on the dropdown toggle to open the menu + userEvent.click(screen.getByTestId('addMembers')); + await wait(); + + // Click on the "Admins" option in the dropdown menu + userEvent.click(screen.getByTestId('newUser')); + await wait(); + + expect(screen.getByTestId('addNewUserModal')).toBeInTheDocument(); + + fireEvent.change(screen.getByTestId('firstNameInput'), { + target: { value: 'Disha' }, + }); + expect(screen.getByTestId('firstNameInput')).toHaveValue('Disha'); + + fireEvent.change(screen.getByTestId('lastNameInput'), { + target: { value: 'Talreja' }, + }); + expect(screen.getByTestId('lastNameInput')).toHaveValue('Talreja'); + + fireEvent.change(screen.getByTestId('emailInput'), { + target: { value: 'test@gmail.com' }, + }); + expect(screen.getByTestId('emailInput')).toHaveValue('test@gmail.com'); + + fireEvent.change(screen.getByTestId('passwordInput'), { + target: { value: 'dishatalreja' }, + }); + userEvent.click(screen.getByTestId('showPassword')); + expect(screen.getByTestId('passwordInput')).toHaveValue('dishatalreja'); + + fireEvent.change(screen.getByTestId('confirmPasswordInput'), { + target: { value: 'disha' }, + }); + userEvent.click(screen.getByTestId('showConfirmPassword')); + expect(screen.getByTestId('confirmPasswordInput')).toHaveValue('disha'); + + userEvent.click(screen.getByTestId('createBtn')); + }); + + test('Throw passwordNotMatch error in add new user modal', async () => { + window.location.assign('/orgpeople/orgid'); + render( + + + + + + + + + , + ); + + // Wait for the component to finish rendering + await wait(); + + // Click on the dropdown toggle to open the menu + userEvent.click(screen.getByTestId('addMembers')); + await wait(); + + // Click on the "Admins" option in the dropdown menu + userEvent.click(screen.getByTestId('newUser')); + await wait(); + + expect(screen.getByTestId('addNewUserModal')).toBeInTheDocument(); + + fireEvent.change(screen.getByTestId('firstNameInput'), { + target: { value: 'Disha' }, + }); + expect(screen.getByTestId('firstNameInput')).toHaveValue('Disha'); + + fireEvent.change(screen.getByTestId('lastNameInput'), { + target: { value: 'Talreja' }, + }); + expect(screen.getByTestId('lastNameInput')).toHaveValue('Talreja'); + + fireEvent.change(screen.getByTestId('passwordInput'), { + target: { value: 'dishatalreja' }, + }); + userEvent.click(screen.getByTestId('showPassword')); + expect(screen.getByTestId('passwordInput')).toHaveValue('dishatalreja'); + + fireEvent.change(screen.getByTestId('confirmPasswordInput'), { + target: { value: 'dishatalreja' }, + }); + userEvent.click(screen.getByTestId('showConfirmPassword')); + expect(screen.getByTestId('confirmPasswordInput')).toHaveValue( + 'dishatalreja', + ); + + userEvent.click(screen.getByTestId('createBtn')); + }); + + test('Testing USERS list', async () => { + window.location.assign('/orgpeople/6401ff65ce8e8406b8f07af1'); + + render( + + + + + + + + + , + ); + await wait(); + + const orgUsers = MOCKS[3]?.result?.data?.users; + expect(orgUsers?.length).toBe(2); + + const dropdownToggles = screen.getAllByTestId('role'); + + dropdownToggles.forEach((dropdownToggle) => { + userEvent.click(dropdownToggle); + }); + + const usersDropdownItem = screen.getByTestId('users'); + userEvent.click(usersDropdownItem); + await wait(); + const btn = screen.getByTestId('searchbtn'); + userEvent.click(btn); + await wait(); + expect(window.location).toBeAt('/orgpeople/6401ff65ce8e8406b8f07af1'); + }); + + test('Testing USERS list with filters', async () => { + window.location.assign('/orgpeople/6401ff65ce8e8406b8f07af2'); + + render( + + + + + + + + + , + ); + await wait(); + + const fullNameInput = screen.getByPlaceholderText(/Enter Full Name/i); + + // Only Full Name + userEvent.type(fullNameInput, searchData.fullNameUser); + const btn = screen.getByTestId('searchbtn'); + userEvent.click(btn); + await wait(); + expect(window.location).toBeAt('/orgpeople/6401ff65ce8e8406b8f07af2'); + }); + + test('Add Member component renders', async () => { + render( + + + + + + + + + , + ); + await wait(); + userEvent.click(screen.getByTestId('addMembers')); + await wait(); + userEvent.click(screen.getByTestId('existingUser')); + await wait(); + const btn = screen.getByTestId('submitBtn'); + userEvent.click(btn); + }); + + test('Datagrid renders with members data', async () => { + render( + + + + + + + , + ); + + await wait(); + const dataGrid = screen.getByRole('grid'); + expect(dataGrid).toBeInTheDocument(); + const removeButtons = screen.getAllByTestId('removeMemberModalBtn'); + userEvent.click(removeButtons[0]); + }); + + test('Datagrid renders with admin data', async () => { + window.location.assign('/orgpeople/orgid'); + render( + + + + + + + , + ); + + await wait(); + const dropdownToggles = screen.getAllByTestId('role'); + dropdownToggles.forEach((dropdownToggle) => { + userEvent.click(dropdownToggle); + }); + const adminDropdownItem = screen.getByTestId('admins'); + userEvent.click(adminDropdownItem); + await wait(); + const removeButtons = screen.getAllByTestId('removeAdminModalBtn'); + userEvent.click(removeButtons[0]); + }); + + test('No Mock Data test', async () => { + window.location.assign('/orgpeople/orgid'); + + render( + + + + + + + + + , + ); + + await wait(); + expect(window.location).toBeAt('/orgpeople/orgid'); + expect(screen.queryByText(/Nothing Found !!/i)).toBeInTheDocument(); + }); +}); diff --git a/src/screens/OrganizationPeople/OrganizationPeople.tsx b/src/screens/OrganizationPeople/OrganizationPeople.tsx new file mode 100644 index 0000000000..24b8f0a2ad --- /dev/null +++ b/src/screens/OrganizationPeople/OrganizationPeople.tsx @@ -0,0 +1,458 @@ +import { useLazyQuery } from '@apollo/client'; +import { Search, Sort } from '@mui/icons-material'; +import { + ORGANIZATIONS_LIST, + ORGANIZATIONS_MEMBER_CONNECTION_LIST, + USER_LIST_FOR_TABLE, +} from 'GraphQl/Queries/Queries'; +import Loader from 'components/Loader/Loader'; +import OrgAdminListCard from 'components/OrgAdminListCard/OrgAdminListCard'; +import OrgPeopleListCard from 'components/OrgPeopleListCard/OrgPeopleListCard'; +import dayjs from 'dayjs'; +import React, { useEffect, useState } from 'react'; +import { Button, Dropdown, Form } from 'react-bootstrap'; +import Row from 'react-bootstrap/Row'; +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 { DataGrid } from '@mui/x-data-grid'; +import type { GridColDef, GridCellParams } from '@mui/x-data-grid'; +import { Stack } from '@mui/material'; +import Avatar from 'components/Avatar/Avatar'; + +function organizationPeople(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'organizationPeople', + }); + const { t: tCommon } = useTranslation('common'); + + document.title = t('title'); + + const location = useLocation(); + const role = location?.state; + + const { orgId: currentUrl } = useParams(); + + const [state, setState] = useState(role?.role || 0); + + const [filterData, setFilterData] = useState({ + firstName_contains: '', + lastName_contains: '', + }); + const [adminFilteredData, setAdminFilteredData] = useState(); + + const [userName, setUserName] = useState(''); + const [showRemoveModal, setShowRemoveModal] = React.useState(false); + const [selectedAdminId, setSelectedAdminId] = React.useState< + string | undefined + >(); + const [selectedMemId, setSelectedMemId] = React.useState< + string | undefined + >(); + const toggleRemoveModal = (): void => { + setShowRemoveModal((prev) => !prev); + }; + const toggleRemoveMemberModal = (id: string): void => { + setSelectedMemId(id); + setSelectedAdminId(undefined); + toggleRemoveModal(); + }; + const toggleRemoveAdminModal = (id: string): void => { + setSelectedAdminId(id); + setSelectedMemId(undefined); + toggleRemoveModal(); + }; + + const { + data: memberData, + loading: memberLoading, + error: memberError, + refetch: memberRefetch, + } = useLazyQuery(ORGANIZATIONS_MEMBER_CONNECTION_LIST, { + variables: { + firstName_contains: '', + lastName_contains: '', + orgId: currentUrl, + }, + })[1]; + + const { + data: adminData, + loading: adminLoading, + error: adminError, + refetch: adminRefetch, + } = useLazyQuery(ORGANIZATIONS_LIST, { + variables: { + id: currentUrl, + }, + })[1]; + + const { + data: usersData, + loading: usersLoading, + error: usersError, + refetch: usersRefetch, + } = useLazyQuery(USER_LIST_FOR_TABLE, { + variables: { + firstName_contains: '', + lastName_contains: '', + }, + })[1]; + + useEffect(() => { + if (state === 0) { + memberRefetch({ + ...filterData, + orgId: currentUrl, + }); + } else if (state === 1) { + adminRefetch({ + id: currentUrl, + }); + setAdminFilteredData(adminData?.organizations[0].admins); + } else { + usersRefetch({ + ...filterData, + }); + } + }, [state, adminData]); + + /* istanbul ignore next */ + if (memberError || usersError || adminError) { + const error = memberError ?? usersError ?? adminError; + toast.error(error?.message); + } + if (memberLoading || usersLoading || adminLoading) { + return ( +
    + +
    + ); + } + + const handleFullNameSearchChange = (e: React.FormEvent): void => { + e.preventDefault(); + /* istanbul ignore next */ + const [firstName, lastName] = userName.split(' '); + const newFilterData = { + firstName_contains: firstName || '', + lastName_contains: lastName || '', + }; + + setFilterData(newFilterData); + + if (state === 0) { + memberRefetch({ + ...newFilterData, + orgId: currentUrl, + }); + } else if (state === 1) { + const filterData = adminData.organizations[0].admins.filter( + (value: { + _id: string; + firstName: string; + lastName: string; + createdAt: string; + }) => { + return (value.firstName + value.lastName) + .toLowerCase() + .includes(userName.toLowerCase()); + }, + ); + setAdminFilteredData(filterData); + } else { + usersRefetch({ + ...newFilterData, + }); + } + }; + + const columns: GridColDef[] = [ + { + field: 'profile', + headerName: tCommon('profile'), + flex: 1, + minWidth: 50, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return params.row?.image ? ( + avatar + ) : ( + + ); + }, + }, + { + field: 'name', + headerName: tCommon('name'), + flex: 2, + minWidth: 150, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return ( + + {params.row?.firstName + ' ' + params.row?.lastName} + + ); + }, + }, + { + field: 'email', + headerName: tCommon('email'), + minWidth: 150, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + flex: 2, + sortable: false, + }, + { + field: 'joined', + headerName: tCommon('joined'), + flex: 2, + minWidth: 100, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return dayjs(params.row.createdAt).format('DD/MM/YYYY'); + }, + }, + { + field: 'action', + headerName: tCommon('action'), + flex: 1, + minWidth: 100, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return state === 1 ? ( + + ) : ( + + ); + }, + }, + ]; + return ( + <> + +
    +
    +
    +
    + { + const { value } = e.target; + setUserName(value); + }} + /> + + +
    +
    + + + + {t('sort')} + + + { + setState(2); + }} + > + + {tCommon('users')} + + + { + setState(0); + }} + > + + + { + setState(1); + }} + > + + + + +
    +
    + +
    +
    +
    +
    + {((state == 0 && memberData) || + (state == 1 && adminFilteredData) || + (state == 2 && usersData)) && ( +
    + row._id} + slots={{ + noRowsOverlay: () => ( + + Nothing Found !! + + ), + }} + sx={{ + '&.MuiDataGrid-root .MuiDataGrid-cell:focus-within': { + outline: 'none !important', + }, + '&.MuiDataGrid-root .MuiDataGrid-columnHeader:focus-within': { + outline: 'none', + }, + '& .MuiDataGrid-row:hover': { + backgroundColor: 'transparent', + }, + '& .MuiDataGrid-row.Mui-hovered': { + backgroundColor: 'transparent', + }, + }} + getRowClassName={() => `${styles.rowBackground}`} + autoHeight + rowHeight={70} + rows={ + state === 0 + ? memberData.organizationsMemberConnection.edges + : state === 1 + ? adminFilteredData + : convertObject(usersData) + } + columns={columns} + isRowSelectable={() => false} + /> +
    + )} + {showRemoveModal && selectedMemId && ( + + )} + {showRemoveModal && selectedAdminId && ( + + )} + + ); +} + +export default organizationPeople; + +// This code is used to remove 'user' object from the array index of userData and directly use store the properties at array index, this formatting is needed for DataGrid. + +interface InterfaceUser { + _id: string; + firstName: string; + lastName: string; + email: string; + image: string; + createdAt: string; +} +interface InterfaceOriginalObject { + users: { user: InterfaceUser }[]; +} +interface InterfaceConvertedObject { + users: InterfaceUser[]; +} +function convertObject(original: InterfaceOriginalObject): InterfaceUser[] { + const convertedObject: InterfaceConvertedObject = { + users: [], + }; + original.users.forEach((item) => { + convertedObject.users.push({ + firstName: item.user?.firstName, + lastName: item.user?.lastName, + email: item.user?.email, + image: item.user?.image, + createdAt: item.user?.createdAt, + _id: item.user?._id, + }); + }); + return convertedObject.users; +} diff --git a/src/screens/OrganizationVenues/OrganizationVenues.module.css b/src/screens/OrganizationVenues/OrganizationVenues.module.css new file mode 100644 index 0000000000..e4ac9d7575 --- /dev/null +++ b/src/screens/OrganizationVenues/OrganizationVenues.module.css @@ -0,0 +1,879 @@ +.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.test.tsx new file mode 100644 index 0000000000..5b8b9933a1 --- /dev/null +++ b/src/screens/OrganizationVenues/OrganizationVenues.test.tsx @@ -0,0 +1,497 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import type { RenderResult } from '@testing-library/react'; +import { + act, + render, + screen, + fireEvent, + 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 OrganizationVenues from './OrganizationVenues'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; +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'; + +const MOCKS = [ + { + request: { + query: VENUE_LIST, + variables: { + orgId: 'orgId', + orderBy: 'capacity_ASC', + where: { + name_starts_with: '', + description_starts_with: undefined, + }, + }, + }, + result: { + data: { + getVenueByOrgId: [ + { + _id: 'venue1', + capacity: 1000, + description: 'Updated description for venue 1', + imageUrl: null, + name: 'Updated Venue 1', + organization: { + __typename: 'Organization', + _id: 'orgId', + }, + __typename: 'Venue', + }, + { + _id: 'venue2', + capacity: 1500, + description: 'Updated description for venue 2', + imageUrl: null, + name: 'Updated Venue 2', + organization: { + __typename: 'Organization', + _id: 'orgId', + }, + __typename: 'Venue', + }, + { + _id: 'venue3', + name: 'Venue with a name longer than 25 characters that should be truncated', + description: + 'Venue description that should be truncated because it is longer than 75 characters', + capacity: 2000, + imageUrl: null, + organization: { + _id: 'orgId', + __typename: 'Organization', + }, + __typename: 'Venue', + }, + ], + }, + }, + }, + { + request: { + query: VENUE_LIST, + variables: { + orgId: 'orgId', + orderBy: 'capacity_DESC', + where: { + name_starts_with: '', + description_starts_with: undefined, + }, + }, + }, + result: { + data: { + getVenueByOrgId: [ + { + _id: 'venue3', + name: 'Venue with a name longer than 25 characters that should be truncated', + description: + 'Venue description that should be truncated because it is longer than 75 characters', + capacity: 2000, + imageUrl: null, + organization: { + _id: 'orgId', + __typename: 'Organization', + }, + __typename: 'Venue', + }, + { + _id: 'venue2', + capacity: 1500, + description: 'Updated description for venue 2', + imageUrl: null, + name: 'Updated Venue 2', + organization: { + __typename: 'Organization', + _id: 'orgId', + }, + __typename: 'Venue', + }, + { + _id: 'venue1', + capacity: 1000, + description: 'Updated description for venue 1', + imageUrl: null, + name: 'Updated Venue 1', + organization: { + __typename: 'Organization', + _id: 'orgId', + }, + __typename: 'Venue', + }, + ], + }, + }, + }, + { + request: { + query: VENUE_LIST, + variables: { + orgId: 'orgId', + orderBy: 'capacity_DESC', + where: { + name_starts_with: 'Updated Venue 1', + description_starts_with: undefined, + }, + }, + }, + result: { + data: { + getVenueByOrgId: [ + { + _id: 'venue1', + capacity: 1000, + description: 'Updated description for venue 1', + imageUrl: null, + name: 'Updated Venue 1', + organization: { + __typename: 'Organization', + _id: 'orgId', + }, + __typename: 'Venue', + }, + ], + }, + }, + }, + { + request: { + query: VENUE_LIST, + variables: { + orgId: 'orgId', + orderBy: 'capacity_DESC', + where: { + name_starts_with: undefined, + description_starts_with: 'Updated description for venue 1', + }, + }, + }, + result: { + data: { + getVenueByOrgId: [ + { + _id: 'venue1', + capacity: 1000, + description: 'Updated description for venue 1', + imageUrl: null, + name: 'Updated Venue 1', + organization: { + __typename: 'Organization', + _id: 'orgId', + }, + __typename: 'Venue', + }, + ], + }, + }, + }, + { + request: { + query: DELETE_VENUE_MUTATION, + variables: { + id: 'venue1', + }, + }, + result: { + data: { + deleteVenue: { + _id: 'venue1', + __typename: 'Venue', + }, + }, + }, + }, + { + request: { + query: DELETE_VENUE_MUTATION, + variables: { + id: 'venue2', + }, + }, + result: { + data: { + deleteVenue: { + _id: 'venue2', + __typename: 'Venue', + }, + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + warning: jest.fn(), + error: jest.fn(), + }, +})); + +const renderOrganizationVenue = (link: ApolloLink): RenderResult => { + return render( + + + + + + } + /> + paramsError} + /> + + + + + , + ); +}; + +describe('OrganizationVenue with missing orgId', () => { + beforeAll(() => { + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: undefined }), + })); + }); + + afterAll(() => { + jest.clearAllMocks(); + }); + test('Redirect to /orglist when orgId is falsy/undefined', async () => { + render( + + + + + + } /> + } + /> + + + + + , + ); + + await waitFor(() => { + const paramsError = screen.getByTestId('paramsError'); + expect(paramsError).toBeInTheDocument(); + }); + }); +}); + +describe('Organisation Venues', () => { + global.alert = jest.fn(); + + beforeAll(() => { + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: 'orgId' }), + })); + }); + + afterAll(() => { + jest.clearAllMocks(); + }); + + test('searches the venue list correctly by Name', async () => { + renderOrganizationVenue(link); + await wait(); + + fireEvent.click(screen.getByTestId('searchByDrpdwn')); + fireEvent.click(screen.getByTestId('name')); + + const searchInput = screen.getByTestId('searchBy'); + fireEvent.change(searchInput, { + target: { value: 'Updated Venue 1' }, + }); + await waitFor(() => { + expect(screen.getByTestId('venue-item1')).toBeInTheDocument(); + expect(screen.queryByTestId('venue-item2')).not.toBeInTheDocument(); + }); + }); + + test('searches the venue list correctly by Description', async () => { + renderOrganizationVenue(link); + await waitFor(() => + expect(screen.getByTestId('orgvenueslist')).toBeInTheDocument(), + ); + + fireEvent.click(screen.getByTestId('searchByDrpdwn')); + fireEvent.click(screen.getByTestId('desc')); + + const searchInput = screen.getByTestId('searchBy'); + fireEvent.change(searchInput, { + target: { value: 'Updated description for venue 1' }, + }); + + await waitFor(() => { + expect(screen.getByTestId('venue-item1')).toBeInTheDocument(); + expect(screen.queryByTestId('venue-item2')).not.toBeInTheDocument(); + }); + }); + + test('sorts the venue list by lowest capacity correctly', async () => { + renderOrganizationVenue(link); + await waitFor(() => + expect(screen.getByTestId('orgvenueslist')).toBeInTheDocument(), + ); + + fireEvent.click(screen.getByTestId('sortVenues')); + fireEvent.click(screen.getByTestId('lowest')); + await waitFor(() => { + expect(screen.getByTestId('venue-item1')).toHaveTextContent( + /Updated Venue 1/i, + ); + expect(screen.getByTestId('venue-item2')).toHaveTextContent( + /Updated Venue 2/i, + ); + }); + }); + + test('sorts the venue list by highest capacity correctly', async () => { + renderOrganizationVenue(link); + await waitFor(() => + expect(screen.getByTestId('orgvenueslist')).toBeInTheDocument(), + ); + + fireEvent.click(screen.getByTestId('sortVenues')); + fireEvent.click(screen.getByTestId('highest')); + await waitFor(() => { + expect(screen.getByTestId('venue-item1')).toHaveTextContent( + /Venue with a name longer .../i, + ); + expect(screen.getByTestId('venue-item2')).toHaveTextContent( + /Updated Venue 2/i, + ); + }); + }); + + test('renders venue name with ellipsis if name is longer than 25 characters', async () => { + renderOrganizationVenue(link); + await waitFor(() => + expect(screen.getByTestId('orgvenueslist')).toBeInTheDocument(), + ); + + const venue = screen.getByTestId('venue-item1'); + expect(venue).toHaveTextContent(/Venue with a name longer .../i); + }); + + test('renders full venue name if name is less than or equal to 25 characters', async () => { + renderOrganizationVenue(link); + await waitFor(() => + expect(screen.getByTestId('orgvenueslist')).toBeInTheDocument(), + ); + + const venueName = screen.getByTestId('venue-item3'); + expect(venueName).toHaveTextContent('Updated Venue 1'); + }); + + test('renders venue description with ellipsis if description is longer than 75 characters', async () => { + renderOrganizationVenue(link); + await waitFor(() => + expect(screen.getByTestId('orgvenueslist')).toBeInTheDocument(), + ); + + const venue = screen.getByTestId('venue-item1'); + expect(venue).toHaveTextContent( + 'Venue description that should be truncated because it is longer than 75 cha...', + ); + }); + + test('renders full venue description if description is less than or equal to 75 characters', async () => { + renderOrganizationVenue(link); + await waitFor(() => + expect(screen.getByTestId('orgvenueslist')).toBeInTheDocument(), + ); + + const venue = screen.getByTestId('venue-item3'); + expect(venue).toHaveTextContent('Updated description for venue 1'); + }); + + test('Render modal to edit venue', async () => { + renderOrganizationVenue(link); + await waitFor(() => + expect(screen.getByTestId('orgvenueslist')).toBeInTheDocument(), + ); + + fireEvent.click(screen.getByTestId('updateVenueBtn1')); + await waitFor(() => { + expect(screen.getByTestId('venueForm')).toBeInTheDocument(); + }); + }); + + test('Render Modal to add event', async () => { + renderOrganizationVenue(link); + await waitFor(() => + expect(screen.getByTestId('orgvenueslist')).toBeInTheDocument(), + ); + + fireEvent.click(screen.getByTestId('createVenueBtn')); + await waitFor(() => { + expect(screen.getByTestId('venueForm')).toBeInTheDocument(); + }); + }); + + test('calls handleDelete when delete button is clicked', async () => { + renderOrganizationVenue(link); + await waitFor(() => + expect(screen.getByTestId('orgvenueslist')).toBeInTheDocument(), + ); + + const deleteButton = screen.getByTestId('deleteVenueBtn3'); + fireEvent.click(deleteButton); + await wait(); + await waitFor(() => { + const deletedVenue = screen.queryByTestId('venue-item3'); + expect(deletedVenue).not.toHaveTextContent(/Updated Venue 2/i); + }); + }); + + test('displays loader when data is loading', () => { + renderOrganizationVenue(link); + expect(screen.getByTestId('spinner-wrapper')).toBeInTheDocument(); + }); + + test('renders without crashing', async () => { + renderOrganizationVenue(link); + waitFor(() => { + expect(screen.findByTestId('orgvenueslist')).toBeInTheDocument(); + }); + }); + + test('renders the venue list correctly', async () => { + renderOrganizationVenue(link); + waitFor(() => { + expect(screen.getByTestId('venueRow2')).toBeInTheDocument(); + expect(screen.getByTestId('venueRow1')).toBeInTheDocument(); + }); + }); +}); diff --git a/src/screens/OrganizationVenues/OrganizationVenues.tsx b/src/screens/OrganizationVenues/OrganizationVenues.tsx new file mode 100644 index 0000000000..6c08733e17 --- /dev/null +++ b/src/screens/OrganizationVenues/OrganizationVenues.tsx @@ -0,0 +1,250 @@ +import React, { useEffect, useState } from 'react'; +import Button from 'react-bootstrap/Button'; +import { useTranslation } from 'react-i18next'; +import styles from './OrganizationVenues.module.css'; +import { errorHandler } from 'utils/errorHandler'; +import { useMutation, useQuery } from '@apollo/client'; +import Col from 'react-bootstrap/Col'; +import { VENUE_LIST } from 'GraphQl/Queries/OrganizationQueries'; +import Loader from 'components/Loader/Loader'; +import { Navigate, useParams } from 'react-router-dom'; +import VenueModal from 'components/Venues/VenueModal'; +import { Dropdown, Form } from 'react-bootstrap'; +import { Search, Sort } from '@mui/icons-material'; +import { DELETE_VENUE_MUTATION } from 'GraphQl/Mutations/VenueMutations'; +import type { InterfaceQueryVenueListItem } from 'utils/interfaces'; +import VenueCard from 'components/Venues/VenueCard'; + +function organizationVenues(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'organizationVenues', + }); + const { t: tCommon } = useTranslation('common'); + + document.title = t('title'); + const [venueModal, setVenueModal] = useState(false); + const [venueModalMode, setVenueModalMode] = useState<'edit' | 'create'>( + 'create', + ); + const [searchTerm, setSearchTerm] = useState(''); + const [searchBy, setSearchBy] = useState<'name' | 'desc'>('name'); + const [sortOrder, setSortOrder] = useState<'highest' | 'lowest'>('highest'); + const [editVenueData, setEditVenueData] = + useState(null); + const [venues, setVenues] = useState([]); + + const { orgId } = useParams(); + if (!orgId) { + return ; + } + + const { + data: venueData, + loading: venueLoading, + error: venueError, + refetch: venueRefetch, + } = useQuery(VENUE_LIST, { + variables: { + orgId: orgId, + orderBy: sortOrder === 'highest' ? 'capacity_DESC' : 'capacity_ASC', + where: { + name_starts_with: searchBy === 'name' ? searchTerm : undefined, + description_starts_with: searchBy === 'desc' ? searchTerm : undefined, + }, + }, + }); + + const [deleteVenue] = useMutation(DELETE_VENUE_MUTATION); + + const handleDelete = async (venueId: string): Promise => { + try { + await deleteVenue({ + variables: { id: venueId }, + }); + venueRefetch(); + } catch (error) { + /* istanbul ignore next */ + errorHandler(t, error); + } + }; + + const handleSearchChange = ( + event: React.ChangeEvent, + ): void => { + setSearchTerm(event.target.value); + }; + + const handleSortChange = (order: 'highest' | 'lowest'): void => { + setSortOrder(order); + }; + + const toggleVenueModal = (): void => { + setVenueModal(!venueModal); + }; + + const showEditVenueModal = (venueItem: InterfaceQueryVenueListItem): void => { + setVenueModalMode('edit'); + setEditVenueData(venueItem); + toggleVenueModal(); + }; + + const showCreateVenueModal = (): void => { + setVenueModalMode('create'); + setEditVenueData(null); + toggleVenueModal(); + }; + /* istanbul ignore next */ + if (venueError) { + errorHandler(t, venueError); + } + + useEffect(() => { + if (venueData && venueData.getVenueByOrgId) { + setVenues(venueData.getVenueByOrgId); + } + }, [venueData]); + + return ( + <> +
    +
    + + +
    +
    +
    + + +
    + +
    +
    + + +
    + {venueLoading ? ( + <> + + + ) : ( +
    + {venues.length ? ( + venues.map( + (venueItem: InterfaceQueryVenueListItem, index: number) => ( + + ), + ) + ) : ( +
    {t('noVenues')}
    + )} +
    + )} +
    + + + + ); +} + +export default organizationVenues; diff --git a/src/screens/PageNotFound/PageNotFound.module.css b/src/screens/PageNotFound/PageNotFound.module.css new file mode 100644 index 0000000000..3c1b9a3413 --- /dev/null +++ b/src/screens/PageNotFound/PageNotFound.module.css @@ -0,0 +1,109 @@ +.notfound { + position: relative; + bottom: 20px; +} + +.notfound h3 { + font-family: 'Roboto', sans-serif; + font-weight: normal; + letter-spacing: 1px; +} + +.notfound .brand span { + margin-top: 50px; + font-size: 40px; +} +.notfound .brand h3 { + font-weight: 300; + margin: 10px 0 0 0; +} +.notfound h1.head { + font-size: 250px; + font-weight: 900; + color: #31bb6b; + letter-spacing: 25px; + margin: 10px 0 0 0; +} +.notfound h1.head span { + position: relative; + display: inline-block; +} +.notfound h1.head span:before, +.notfound h1.head span:after { + position: absolute; + top: 50%; + width: 50%; + height: 1px; + background: #fff; + content: ''; +} +.notfound h1.head span:before { + left: -55%; +} +.notfound h1.head span:after { + right: -55%; +} + +@media (max-width: 1024px) { + .notfound h1.head { + font-size: 200px; + letter-spacing: 25px; + } +} + +@media (max-width: 768px) { + .notfound h1.head { + font-size: 150px; + letter-spacing: 25px; + } +} + +@media (max-width: 640px) { + .notfound h1.head { + font-size: 150px; + letter-spacing: 0; + } +} + +@media (max-width: 480px) { + .notfound .brand h3 { + font-size: 20px; + } + .notfound h1.head { + font-size: 130px; + letter-spacing: 0; + } + .notfound h1.head span:before, + .notfound h1.head span:after { + width: 40%; + } + .notfound h1.head span:before { + left: -45%; + } + .notfound h1.head span:after { + right: -45%; + } + .notfound p { + font-size: 18px; + } +} + +@media (max-width: 320px) { + .notfound .brand h3 { + font-size: 16px; + } + .notfound h1.head { + font-size: 100px; + letter-spacing: 0; + } + .notfound h1.head span:before, + .notfound h1.head span:after { + width: 25%; + } + .notfound h1.head span:before { + left: -30%; + } + .notfound h1.head span:after { + right: -30%; + } +} diff --git a/src/screens/PageNotFound/PageNotFound.test.tsx b/src/screens/PageNotFound/PageNotFound.test.tsx new file mode 100644 index 0000000000..501d9f7ef3 --- /dev/null +++ b/src/screens/PageNotFound/PageNotFound.test.tsx @@ -0,0 +1,59 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { I18nextProvider } from 'react-i18next'; + +import { store } from 'state/store'; +import PageNotFound from './PageNotFound'; +import i18nForTest from 'utils/i18nForTest'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem } = useLocalStorage(); + +describe('Testing Page not found component', () => { + test('Component should be rendered properly for User', () => { + //setItem('AdminFor', undefined); + render( + + + + + + + , + ); + + expect(screen.getByText(/Talawa User/i)).toBeTruthy(); + expect(screen.getByText(/404/i)).toBeTruthy(); + expect( + screen.getByText(/Oops! The Page you requested was not found!/i), + ).toBeTruthy(); + expect(screen.getByText(/Back to Home/i)).toBeTruthy(); + }); + + test('Component should be rendered properly for ADMIN or SUPERADMIN', () => { + setItem('AdminFor', [ + { + _id: '6537904485008f171cf29924', + __typename: 'Organization', + }, + ]); + render( + + + + + + + , + ); + + expect(screen.getByText(/Talawa Admin Portal/i)).toBeTruthy(); + expect(screen.getByText(/404/i)).toBeTruthy(); + expect( + screen.getByText(/Oops! The Page you requested was not found!/i), + ).toBeTruthy(); + expect(screen.getByText(/Back to Home/i)).toBeTruthy(); + }); +}); diff --git a/src/screens/PageNotFound/PageNotFound.tsx b/src/screens/PageNotFound/PageNotFound.tsx new file mode 100644 index 0000000000..92f4a98f7e --- /dev/null +++ b/src/screens/PageNotFound/PageNotFound.tsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import useLocalStorage from 'utils/useLocalstorage'; + +import styles from './PageNotFound.module.css'; +import Logo from 'assets/images/talawa-logo-200x200.png'; + +const PageNotFound = (): JSX.Element => { + const { t } = useTranslation('translation', { + keyPrefix: 'pageNotFound', + }); + const { t: tCommon } = useTranslation('common'); + const { t: tErrors } = useTranslation('errors'); + + document.title = t('title'); + + const { getItem } = useLocalStorage(); + const adminFor = getItem('AdminFor'); + + return ( +
    +
    +
    + Logo + {adminFor != undefined ? ( +

    + {tCommon('talawaAdminPortal')} +

    + ) : ( +

    {t('talawaUser')}

    + )} +
    +

    + {t('404')} +

    +

    {tErrors('notFoundMsg')}

    + {adminFor != undefined ? ( + + {t('backToHome')} + + ) : ( + + {t('backToHome')} + + )} +
    +
    + ); +}; + +export default PageNotFound; diff --git a/src/screens/Requests/Requests.module.css b/src/screens/Requests/Requests.module.css new file mode 100644 index 0000000000..b23869c8d0 --- /dev/null +++ b/src/screens/Requests/Requests.module.css @@ -0,0 +1,120 @@ +.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: 50%; + position: relative; +} + +.btnsContainer input { + box-sizing: border-box; + background: #fcfcfc; + border: 1px solid #dddddd; + box-shadow: 5px 5px 4px rgba(49, 187, 107, 0.12); + border-radius: 8px; +} + +.btnsContainer .inputContainer button { + width: 55px; + height: 55px; +} + +.listBox { + width: 100%; + flex: 1; +} + +.listTable { + width: 100%; + box-sizing: border-box; + background: #ffffff; + border: 1px solid #0000001f; + border-radius: 24px; +} + +.listBox .customTable { + margin-bottom: 0%; +} + +.requestsTable thead th { + font-size: 20px; + font-weight: 400; + line-height: 24px; + letter-spacing: 0em; + text-align: left; + color: #000000; + border-bottom: 1px solid #dddddd; + padding: 1.5rem; +} + +.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 button { + margin-bottom: 1rem; + margin-right: 0; + width: 100%; + } +} diff --git a/src/screens/Requests/Requests.test.tsx b/src/screens/Requests/Requests.test.tsx new file mode 100644 index 0000000000..bf1a533870 --- /dev/null +++ b/src/screens/Requests/Requests.test.tsx @@ -0,0 +1,292 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { act, 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 Requests from './Requests'; +import { + EMPTY_MOCKS, + MOCKS_WITH_ERROR, + MOCKS, + MOCKS2, + EMPTY_REQUEST_MOCKS, + MOCKS3, + MOCKS4, +} from './RequestsMocks'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem, removeItem } = useLocalStorage(); + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(EMPTY_MOCKS, true); +const link3 = new StaticMockLink(EMPTY_REQUEST_MOCKS, true); +const link4 = new StaticMockLink(MOCKS2, true); +const link5 = new StaticMockLink(MOCKS_WITH_ERROR, true); +const link6 = new StaticMockLink(MOCKS3, true); +const link7 = new StaticMockLink(MOCKS4, true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +beforeEach(() => { + setItem('id', 'user1'); + setItem('AdminFor', [{ _id: 'org1', __typename: 'Organization' }]); + setItem('SuperAdmin', false); +}); + +afterEach(() => { + localStorage.clear(); +}); + +describe('Testing Requests screen', () => { + test('Component should be rendered properly', async () => { + const loadMoreRequests = jest.fn(); + render( + + + + + + + + + , + ); + + await wait(); + expect(screen.getByTestId('testComp')).toBeInTheDocument(); + expect(screen.getByText('Scott Tony')).toBeInTheDocument(); + }); + + test(`Component should be rendered properly when user is not Admin + and or userId does not exists in localstorage`, async () => { + setItem('id', ''); + removeItem('AdminFor'); + removeItem('SuperAdmin'); + render( + + + + + + + + + , + ); + + await wait(); + }); + + test('Component should be rendered properly when user is Admin', async () => { + render( + + + + + + + + + , + ); + + await wait(); + }); + + test('Redirecting on error', async () => { + setItem('SuperAdmin', true); + render( + + + + + + + + + , + ); + + await wait(); + expect(window.location.href).toEqual('http://localhost/'); + }); + + test('Testing Search requests 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(); + + 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 () => { + render( + + + + + + + + + , + ); + + await wait(); + + const search = 'hello{enter}'; + await act(() => + userEvent.type(screen.getByTestId(/searchByName/i), search), + ); + }); + + test('Testing Request data is not present', async () => { + render( + + + + + + + + + , + ); + + await wait(); + expect(screen.getByText(/No Membership Requests Found/i)).toBeTruthy(); + }); + + test('Should render warning alert when there are no organizations', async () => { + render( + + + + + + + + + + , + ); + + await wait(200); + expect(screen.queryByText('Organizations Not Found')).toBeInTheDocument(); + expect( + screen.queryByText('Please create an organization through dashboard'), + ).toBeInTheDocument(); + }); + + 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('Should render properly when there are no organizations present in requestsData', async () => { + render( + + + + + + + + + + , + ); + + await wait(); + }); + + test('check for rerendering', async () => { + const { rerender } = render( + + + + + + + + + + , + ); + + await wait(); + rerender( + + + + + + + + + + , + ); + await wait(); + }); +}); diff --git a/src/screens/Requests/Requests.tsx b/src/screens/Requests/Requests.tsx new file mode 100644 index 0000000000..a779bd414c --- /dev/null +++ b/src/screens/Requests/Requests.tsx @@ -0,0 +1,311 @@ +import { useQuery } from '@apollo/client'; +import React, { useEffect, useState } from 'react'; +import { Form, Table } from 'react-bootstrap'; +import Button from 'react-bootstrap/Button'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; +import { Search } from '@mui/icons-material'; +import { + MEMBERSHIP_REQUEST, + ORGANIZATION_CONNECTION_LIST, +} from 'GraphQl/Queries/Queries'; +import TableLoader from 'components/TableLoader/TableLoader'; +import RequestsTableItem from 'components/RequestsTableItem/RequestsTableItem'; +import InfiniteScroll from 'react-infinite-scroll-component'; +import type { InterfaceQueryMembershipRequestsListItem } from 'utils/interfaces'; +import styles from './Requests.module.css'; +import useLocalStorage from 'utils/useLocalstorage'; +import { useParams } from 'react-router-dom'; + +interface InterfaceRequestsListItem { + _id: string; + user: { + firstName: string; + lastName: string; + email: string; + }; +} + +const Requests = (): JSX.Element => { + const { t } = useTranslation('translation', { keyPrefix: 'requests' }); + const { t: tCommon } = useTranslation('common'); + + document.title = t('title'); + + const { getItem } = useLocalStorage(); + + const perPageResult = 8; + const [isLoading, setIsLoading] = useState(true); + const [hasMore, setHasMore] = useState(true); + const [isLoadingMore, setIsLoadingMore] = useState(false); + const [searchByName, setSearchByName] = useState(''); + const userRole = getItem('SuperAdmin') + ? 'SUPERADMIN' + : getItem('AdminFor') + ? 'ADMIN' + : 'USER'; + const { orgId = '' } = useParams(); + const organizationId = orgId; + + const { data, loading, fetchMore, refetch } = useQuery(MEMBERSHIP_REQUEST, { + variables: { + id: organizationId, + first: perPageResult, + skip: 0, + firstName_contains: '', + }, + notifyOnNetworkStatusChange: true, + }); + + const { data: orgsData } = useQuery(ORGANIZATION_CONNECTION_LIST); + const [displayedRequests, setDisplayedRequests] = useState( + data?.organizations[0]?.membershipRequests || [], + ); + + // Manage loading more state + useEffect(() => { + if (!data) { + return; + } + + const membershipRequests = data.organizations[0].membershipRequests; + + if (membershipRequests.length < perPageResult) { + setHasMore(false); + } + + setDisplayedRequests(membershipRequests); + }, [data]); + + // To clear the search when the component is unmounted + useEffect(() => { + return () => { + setSearchByName(''); + }; + }, []); + + // Warn if there is no organization + useEffect(() => { + if (!orgsData) { + return; + } + + if (orgsData.organizationsConnection.length === 0) { + toast.warning(t('noOrgError')); + } + }, [orgsData]); + + // Send to orgList page if user is not admin + useEffect(() => { + if (userRole != 'ADMIN' && userRole != 'SUPERADMIN') { + window.location.assign('/orglist'); + } + }, []); + + // Manage the loading state + useEffect(() => { + if (loading && isLoadingMore == false) { + setIsLoading(true); + } else { + setIsLoading(false); + } + }, [loading]); + + const handleSearch = (value: string): void => { + setSearchByName(value); + if (value === '') { + resetAndRefetch(); + return; + } + refetch({ + id: organizationId, + firstName_contains: value, + // Later on we can add several search and filter options + }); + }; + + const handleSearchByEnter = ( + e: React.KeyboardEvent, + ): void => { + if (e.key === 'Enter') { + const { value } = e.currentTarget; + handleSearch(value); + } + }; + + const handleSearchByBtnClick = (): void => { + const inputElement = document.getElementById( + 'searchRequests', + ) as HTMLInputElement; + const inputValue = inputElement?.value || ''; + handleSearch(inputValue); + }; + + const resetAndRefetch = (): void => { + refetch({ + first: perPageResult, + skip: 0, + firstName_contains: '', + }); + setHasMore(true); + }; + /* istanbul ignore next */ + const loadMoreRequests = (): void => { + setIsLoadingMore(true); + fetchMore({ + variables: { + id: organizationId, + skip: data?.organizations?.[0]?.membershipRequests?.length || 0, + firstName_contains: searchByName, + }, + updateQuery: ( + prev: InterfaceQueryMembershipRequestsListItem | undefined, + { + fetchMoreResult, + }: { + fetchMoreResult: InterfaceQueryMembershipRequestsListItem | undefined; + }, + ): InterfaceQueryMembershipRequestsListItem | undefined => { + setIsLoadingMore(false); + if (!fetchMoreResult) return prev; + const newMembershipRequests = + fetchMoreResult.organizations[0].membershipRequests || []; + if (newMembershipRequests.length < perPageResult) { + setHasMore(false); + } + return { + organizations: [ + { + _id: organizationId, + membershipRequests: [ + ...(prev?.organizations[0].membershipRequests || []), + ...newMembershipRequests, + ], + }, + ], + }; + }, + }); + }; + + const headerTitles: string[] = [ + t('sl_no'), + tCommon('name'), + tCommon('email'), + t('accept'), + t('reject'), + ]; + + return ( + <> + {/* Buttons Container */} +
    +
    +
    + + +
    +
    +
    + {!isLoading && orgsData?.organizationsConnection.length === 0 ? ( +
    +

    {t('noOrgErrorTitle')}

    +
    {t('noOrgErrorDescription')}
    +
    + ) : !isLoading && + data && + displayedRequests.length === 0 && + searchByName.length > 0 ? ( +
    +

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

    +
    + ) : !isLoading && data && displayedRequests.length === 0 ? ( +
    +

    {t('noRequestsFound')}

    +
    + ) : ( +
    + {isLoading ? ( + + ) : ( + + } + hasMore={hasMore} + className={styles.listTable} + data-testid="requests-list" + endMessage={ +
    +
    {tCommon('endOfResults')}
    +
    + } + > + + + + {headerTitles.map((title: string, index: number) => { + return ( + + ); + })} + + + + {data && + displayedRequests.map( + (request: InterfaceRequestsListItem, index: number) => { + return ( + + ); + }, + )} + +
    + {title} +
    +
    + )} +
    + )} + + ); +}; + +export default Requests; diff --git a/src/screens/Requests/RequestsMocks.ts b/src/screens/Requests/RequestsMocks.ts new file mode 100644 index 0000000000..6dc22dd58e --- /dev/null +++ b/src/screens/Requests/RequestsMocks.ts @@ -0,0 +1,573 @@ +import { + MEMBERSHIP_REQUEST, + ORGANIZATION_CONNECTION_LIST, +} from 'GraphQl/Queries/Queries'; + +export const EMPTY_REQUEST_MOCKS = [ + { + request: { + query: ORGANIZATION_CONNECTION_LIST, + }, + result: { + data: { + organizationsConnection: [ + { + _id: 'org1', + image: null, + creator: { + firstName: 'John', + lastName: 'Doe', + }, + name: 'Palisadoes', + members: [ + { + _id: 'user1', + }, + ], + admins: [ + { + _id: 'user1', + }, + ], + createdAt: '09/11/2001', + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + }, + ], + }, + }, + }, + { + request: { + query: MEMBERSHIP_REQUEST, + variables: { + id: '', + skip: 0, + first: 8, + firstName_contains: '', + }, + }, + result: { + data: { + organizations: [ + { + _id: 'org1', + membershipRequests: [], + }, + ], + }, + }, + }, +]; + +export const MOCKS = [ + { + request: { + query: ORGANIZATION_CONNECTION_LIST, + }, + result: { + data: { + organizationsConnection: [ + { + _id: 'org1', + image: null, + creator: { + firstName: 'John', + lastName: 'Doe', + }, + name: 'Palisadoes', + members: [ + { + _id: 'user1', + }, + ], + admins: [ + { + _id: 'user1', + }, + ], + createdAt: '09/11/2001', + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + }, + ], + }, + }, + }, + { + request: { + query: MEMBERSHIP_REQUEST, + variables: { + id: '', + skip: 0, + first: 8, + firstName_contains: '', + }, + }, + result: { + data: { + organizations: [ + { + _id: '', + membershipRequests: [ + { + _id: '1', + user: { + _id: 'user2', + firstName: 'Scott', + lastName: 'Tony', + email: 'testuser3@example.com', + }, + }, + { + _id: '2', + user: { + _id: 'user3', + firstName: 'Teresa', + lastName: 'Bradley', + email: 'testuser4@example.com', + }, + }, + ], + }, + ], + }, + }, + }, +]; + +export const MOCKS4 = [ + { + request: { + query: ORGANIZATION_CONNECTION_LIST, + }, + result: { + data: { + organizationsConnection: [ + { + _id: 'org1', + image: null, + creator: { + firstName: 'John', + lastName: 'Doe', + }, + name: 'Palisadoes', + members: [ + { + _id: 'user1', + }, + ], + admins: [ + { + _id: 'user1', + }, + ], + createdAt: '09/11/2001', + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + }, + ], + }, + }, + }, + { + request: { + query: MEMBERSHIP_REQUEST, + variables: { + id: '', + skip: 0, + first: 8, + firstName_contains: '', + }, + }, + result: { + data: { + organizations: [ + { + _id: '', + membershipRequests: [ + { + _id: '1', + user: { + _id: 'user2', + firstName: 'Scott', + lastName: 'Tony', + email: 'testuser3@example.com', + }, + }, + { + _id: '2', + user: { + _id: 'user3', + firstName: 'Teresa', + lastName: 'Bradley', + email: 'testuser4@example.com', + }, + }, + { + _id: '3', + user: { + _id: 'user4', + firstName: 'Jesse', + lastName: 'Hart', + email: 'testuser5@example.com', + }, + }, + { + _id: '4', + user: { + _id: 'user5', + firstName: 'Lena', + lastName: 'Mcdonald', + email: 'testuser6@example.com', + }, + }, + { + _id: '5', + user: { + _id: 'user6', + firstName: 'David', + lastName: 'Smith', + email: 'testuser7@example.com', + }, + }, + { + _id: '6', + user: { + _id: 'user7', + firstName: 'Emily', + lastName: 'Johnson', + email: 'testuser8@example.com', + }, + }, + { + _id: '7', + user: { + _id: 'user8', + firstName: 'Michael', + lastName: 'Davis', + email: 'testuser9@example.com', + }, + }, + { + _id: '8', + user: { + _id: 'user9', + firstName: 'Sarah', + lastName: 'Wilson', + email: 'testuser10@example.com', + }, + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: MEMBERSHIP_REQUEST, + variables: { + id: '', + skip: 8, + first: 16, + firstName_contains: '', + }, + }, + result: { + data: { + organizations: [ + { + _id: '', + membershipRequests: [ + { + _id: '9', + user: { + _id: 'user10', + firstName: 'Daniel', + lastName: 'Brown', + email: 'testuser11@example.com', + }, + }, + { + _id: '10', + user: { + _id: 'user11', + firstName: 'Jessica', + lastName: 'Martinez', + email: 'testuser12@example.com', + }, + }, + { + _id: '11', + user: { + _id: 'user12', + firstName: 'Matthew', + lastName: 'Taylor', + email: 'testuser13@example.com', + }, + }, + { + _id: '12', + user: { + _id: 'user13', + firstName: 'Amanda', + lastName: 'Anderson', + email: 'testuser14@example.com', + }, + }, + { + _id: '13', + user: { + _id: 'user14', + firstName: 'Christopher', + lastName: 'Thomas', + email: 'testuser15@example.com', + }, + }, + { + _id: '14', + user: { + _id: 'user15', + firstName: 'Ashley', + lastName: 'Hernandez', + email: 'testuser16@example.com', + }, + }, + { + _id: '15', + user: { + _id: 'user16', + firstName: 'Andrew', + lastName: 'Young', + email: 'testuser17@example.com', + }, + }, + { + _id: '16', + user: { + _id: 'user17', + firstName: 'Nicole', + lastName: 'Garcia', + email: 'testuser18@example.com', + }, + }, + ], + }, + ], + }, + }, + }, +]; + +export const MOCKS2 = [ + { + request: { + query: ORGANIZATION_CONNECTION_LIST, + }, + result: { + data: { + organizationsConnection: [ + { + _id: 'org1', + image: null, + creator: { + firstName: 'John', + lastName: 'Doe', + }, + name: 'Palisadoes', + members: [ + { + _id: 'user1', + }, + ], + admins: [ + { + _id: 'user1', + }, + ], + createdAt: '09/11/2001', + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + }, + ], + }, + }, + }, + { + request: { + query: MEMBERSHIP_REQUEST, + variables: { + id: 'org1', + skip: 0, + first: 8, + firstName_contains: '', + }, + }, + result: { + data: { + organizations: [ + { + _id: 'org1', + membershipRequests: [ + { + _id: '1', + user: { + _id: 'user2', + firstName: 'Scott', + lastName: 'Tony', + email: 'testuser3@example.com', + }, + }, + ], + }, + ], + }, + }, + }, +]; + +export const MOCKS3 = [ + { + request: { + query: ORGANIZATION_CONNECTION_LIST, + }, + result: { + data: { + organizationsConnection: [ + { + _id: 'org1', + image: null, + creator: { + firstName: 'John', + lastName: 'Doe', + }, + name: 'Palisadoes', + members: [ + { + _id: 'user1', + }, + ], + admins: [ + { + _id: 'user1', + }, + ], + createdAt: '09/11/2001', + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + }, + ], + }, + }, + }, + { + request: { + query: MEMBERSHIP_REQUEST, + variables: { + id: 'org1', + skip: 0, + first: 8, + firstName_contains: '', + }, + }, + result: { + data: { + organizations: [], + }, + }, + }, +]; + +export const EMPTY_MOCKS = [ + { + request: { + query: MEMBERSHIP_REQUEST, + variables: { + id: 'org1', + skip: 0, + first: 8, + firstName_contains: '', + }, + }, + result: { + data: { + organizations: [ + { + _id: 'org1', + membershipRequests: [], + }, + ], + }, + }, + }, + { + request: { + query: ORGANIZATION_CONNECTION_LIST, + }, + result: { + data: { + organizationsConnection: [], + }, + }, + }, +]; + +export const MOCKS_WITH_ERROR = [ + { + request: { + query: MEMBERSHIP_REQUEST, + variables: { + first: 0, + skip: 0, + id: '1', + firstName_contains: '', + }, + }, + }, + { + request: { + query: ORGANIZATION_CONNECTION_LIST, + }, + }, +]; diff --git a/src/screens/UserPortal/Chat/Chat.module.css b/src/screens/UserPortal/Chat/Chat.module.css new file mode 100644 index 0000000000..3600f6720b --- /dev/null +++ b/src/screens/UserPortal/Chat/Chat.module.css @@ -0,0 +1,216 @@ +.containerHeight { + padding: 1rem 1.5rem 0 calc(300px); + height: 100vh; +} + +.expand { + padding-left: 4rem; + animation: moveLeft 0.9s ease-in-out; +} + +.contract { + padding-left: calc(300px); + animation: moveRight 0.5s ease-in-out; +} + +.collapseSidebarButton { + position: fixed; + height: 40px; + bottom: 0; + z-index: 9999; + width: 300px; + background-color: rgba(245, 245, 245, 0.7); + color: black; + border: none; + border-radius: 0px; +} + +.collapseSidebarButton:hover, +.opendrawer:hover { + opacity: 1; + color: black !important; +} + +.containerHeight { + height: 100vh; +} + +.mainContainer { + width: 50%; + margin-left: 20px; + flex-grow: 3; + max-height: 100%; + overflow: auto; + display: flex; + flex-direction: row; + border: 1px solid rgb(220, 220, 220); + margin-top: 15px; + border-radius: 24px; + background-color: white; +} + +.chatContainer { + flex-grow: 6; + display: flex; + flex-direction: column; + margin: 20px; + border: 1px solid rgb(220, 220, 220); + border-radius: 24px; + overflow-y: scroll; + margin-left: 0px; +} + +.chatContainer::-webkit-scrollbar { + display: none; +} + +.contactContainer { + flex-grow: 1; + display: flex; + flex-direction: column; + width: 25%; + overflow-y: scroll; +} + +.addChatContainer { + margin: 0 20px; + padding: 20px 0px 10px 0px; + border-bottom: 2px solid black; +} + +.contactListContainer { + /* flex-grow: 1; */ + /* margin: 15px 10px; */ +} + +.chatHeadingContainer { + padding: 10px; +} + +.borderNone { + border: none; +} + +.accordion-button:focus { + box-shadow: none; +} + +.accordion-button:not(.collapsed) { + color: #212529; + background-color: white; +} + +.chatType { + --bs-accordion-btn-bg: white; + --bs-accordion-active-bg: white; + --bs-accordion-active-color: black; + --bs-accordion-btn-focus-box-shadow: none; + --bs-accordion-border-width: 0px; +} + +.chatType > button { + padding-bottom: 0; +} + +.createChat { + background-color: white; + border: none; +} + +.opendrawer { + position: fixed; + display: flex; + align-items: center; + justify-content: center; + top: 0; + left: 0; + width: 40px; + height: 100vh; + z-index: 9999; + background-color: rgba(245, 245, 245); + border: none; + border-radius: 0px; + margin-right: 20px; + color: black; +} + +.opendrawer:hover { + transition: background-color 0.5s ease; + background-color: var(--bs-primary); +} +.collapseSidebarButton:hover { + transition: background-color 0.5s ease; + background-color: var(--bs-primary); +} + +.customToggle { + padding: 0; + background: none; + border: none; + margin-right: 1rem; + --bs-btn-active-bg: none; +} +.customToggle svg { + color: black; +} + +.customToggle::after { + content: none; +} +.customToggle:hover, +.customToggle:focus, +.customToggle:active { + background: none; + border: none; +} +.customToggle svg { + color: black; +} + +@media (max-width: 1120px) { + .collapseSidebarButton { + width: calc(250px); + } +} + +@media (max-height: 650px) { + .collapseSidebarButton { + width: 250px; + height: 20px; + } + .opendrawer { + width: 30px; + } +} + +/* For tablets */ +@media (max-width: 820px) { + .containerHeight { + height: 100vh; + padding: 2rem; + } + + .contract, + .expand { + animation: none; + } + + .opendrawer { + width: 25px; + } + + .collapseSidebarButton { + width: 100%; + left: 0; + right: 0; + } +} + +.accordionBody { + height: calc(100vh / 2 - 2rem - 60px) !important; + overflow-y: scroll; +} + +.accordionBody::-webkit-scrollbar { + display: none; +} diff --git a/src/screens/UserPortal/Chat/Chat.test.tsx b/src/screens/UserPortal/Chat/Chat.test.tsx new file mode 100644 index 0000000000..bf41dcbe9b --- /dev/null +++ b/src/screens/UserPortal/Chat/Chat.test.tsx @@ -0,0 +1,2304 @@ +import React from 'react'; +import { act, fireEvent, render, screen } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider, useTranslation } from 'react-i18next'; + +import { + DIRECT_CHATS_LIST, + 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 { + MESSAGE_SENT_TO_DIRECT_CHAT, + MESSAGE_SENT_TO_GROUP_CHAT, +} from 'GraphQl/Mutations/OrganizationMutations'; +import { + DIRECT_CHAT_BY_ID, + GROUP_CHAT_BY_ID, + GROUP_CHAT_LIST, +} from 'GraphQl/Queries/PlugInQueries'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem } = useLocalStorage(); + +const MOCKS = [ + { + request: { + query: GROUP_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + groupChatsByUserId: [ + { + _id: '1', + creator: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + }, + messages: { + _id: '1', + createdAt: '', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@email.com', + }, + }, + title: 'Test GroupChat', + organization: { + _id: '1', + name: 'Test Org', + }, + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@email.com', + image: 'img', + }, + ], + }, + { + _id: '2', + creator: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + }, + messages: { + _id: '1', + createdAt: '', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@email.com', + }, + }, + title: 'Test GroupChat', + organization: { + _id: '1', + name: 'Test Org', + }, + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@email.com', + image: 'img', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + groupChatsByUserId: [ + { + _id: '1', + creator: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + }, + messages: { + _id: '1', + createdAt: '', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@email.com', + }, + }, + title: 'Test GroupChat', + organization: { + _id: '1', + name: 'Test Org', + }, + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@email.com', + image: 'img', + }, + ], + }, + { + _id: '2', + creator: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + }, + messages: { + _id: '1', + createdAt: '', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@email.com', + }, + }, + title: 'Test GroupChat', + organization: { + _id: '1', + name: 'Test Org', + }, + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@email.com', + image: 'img', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + groupChatsByUserId: [ + { + _id: '1', + creator: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + }, + messages: { + _id: '1', + createdAt: '', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@email.com', + }, + }, + title: 'Test GroupChat', + organization: { + _id: '1', + name: 'Test Org', + }, + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@email.com', + image: 'img', + }, + ], + }, + { + _id: '1', + creator: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + }, + messages: { + _id: '1', + createdAt: '', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@email.com', + }, + }, + title: 'Test GroupChat', + organization: { + _id: '1', + name: 'Test Org', + }, + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@email.com', + image: 'img', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: DIRECT_CHATS_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + directChatsByUserID: [ + { + _id: '666c88dd92e995354d98527c', + creator: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '668930bae43ce54e6e302cf1', + createdAt: '2024-07-06T11:55:38.933Z', + messageContent: 'hJnkank', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + { + _id: '666f09c892e995354d98a5ee', + creator: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '6676932692e995354d98ab7f', + createdAt: '2024-06-22T09:02:30.776Z', + messageContent: 'hii', + receiver: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + ], + }, + }, + }, + { + request: { + query: DIRECT_CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + directChatsByUserID: [ + { + _id: '666c88dd92e995354d98527c', + creator: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '668930bae43ce54e6e302cf1', + createdAt: '2024-07-06T11:55:38.933Z', + messageContent: 'hJnkank', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + { + _id: '666f09c892e995354d98a5ee', + creator: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '6676932692e995354d98ab7f', + createdAt: '2024-06-22T09:02:30.776Z', + messageContent: 'hii', + receiver: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + ], + }, + }, + }, + { + request: { + query: DIRECT_CHATS_LIST, + variables: { + id: '', + }, + }, + result: { + data: { + directChatsByUserID: [ + { + _id: '666c88dd92e995354d98527c', + creator: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '668930bae43ce54e6e302cf1', + createdAt: '2024-07-06T11:55:38.933Z', + messageContent: 'hJnkank', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + email: 'testadmin1@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + { + _id: '666f09c892e995354d98a5ee', + creator: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + messages: [ + { + _id: '6676932692e995354d98ab7f', + createdAt: '2024-06-22T09:02:30.776Z', + messageContent: 'hii', + receiver: { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + __typename: 'User', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + __typename: 'User', + }, + __typename: 'DirectChatMessage', + }, + ], + organization: { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + __typename: 'Organization', + }, + users: [ + { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'testsuperadmin@example.com', + image: null, + __typename: 'User', + }, + { + _id: '67378abd85008f171cf2990d', + firstName: 'Darcy', + lastName: 'Wilf', + email: 'testadmin3@example.com', + image: null, + __typename: 'User', + }, + ], + __typename: 'DirectChat', + }, + ], + }, + }, + }, +]; + +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_GROUP_CHAT_MOCK = [ + { + request: { + query: MESSAGE_SENT_TO_GROUP_CHAT, + variables: { + userId: null, + }, + }, + result: { + data: { + messageSentToGroupChat: { + _id: '668ec1f1364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_GROUP_CHAT, + variables: { + userId: '2', + }, + }, + result: { + data: { + messageSentToGroupChat: { + _id: '668ec1f1df364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_GROUP_CHAT, + variables: { + userId: '1', + }, + }, + result: { + data: { + messageSentToGroupChat: { + _id: '668ec1f13603ac4697a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, +]; + +const MESSAGE_SENT_TO_DIRECT_CHAT_MOCK = [ + { + request: { + query: MESSAGE_SENT_TO_DIRECT_CHAT, + variables: { + userId: '1', + }, + }, + result: { + data: { + messageSentToDirectChat: { + _id: '668ec1f1364e03ac4697a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + image: '', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_DIRECT_CHAT, + variables: { + userId: '2', + }, + }, + result: { + data: { + messageSentToDirectChat: { + _id: '668ec1f1364e03ac4697vgfa151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + image: '', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_DIRECT_CHAT, + variables: { + userId: null, + }, + }, + result: { + data: { + messageSentToDirectChat: { + _id: '6ec1f1364e03ac4697a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + receiver: { + _id: '65378abd85008f171cf2990d', + firstName: 'Vyvyan', + lastName: 'Kerry', + image: '', + }, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, +]; + +const DIRECT_CHAT_BY_ID_QUERY_MOCK = [ + { + request: { + query: DIRECT_CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + directChatById: { + _id: '1', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + receiver: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: DIRECT_CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + directChatById: { + _id: '1', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + receiver: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: DIRECT_CHAT_BY_ID, + variables: { + id: '', + }, + }, + result: { + data: { + directChatById: { + _id: '1', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + receiver: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: DIRECT_CHAT_BY_ID, + variables: { + id: '2', + }, + }, + result: { + data: { + directChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + receiver: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: DIRECT_CHAT_BY_ID, + variables: { + id: null, + }, + }, + result: { + data: { + directChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + receiver: { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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 GROUP_CHAT_BY_ID_QUERY_MOCK = [ + { + request: { + query: GROUP_CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + groupChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + title: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: GROUP_CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + groupChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + title: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: GROUP_CHAT_BY_ID, + variables: { + id: '', + }, + }, + result: { + data: { + groupChatById: { + _id: '1', + createdAt: '2345678903456', + title: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: GROUP_CHAT_BY_ID, + variables: { + id: '2', + }, + }, + result: { + data: { + groupChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + title: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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: GROUP_CHAT_BY_ID, + variables: { + id: null, + }, + }, + result: { + data: { + groupChatById: { + _id: '65844efc814dd4003db811c4', + createdAt: '2345678903456', + title: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + 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, + ...DIRECT_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_DIRECT_CHAT_MOCK, + ...MESSAGE_SENT_TO_GROUP_CHAT_MOCK, + ...UserConnectionListMock, + ...MOCKS, + ]; + + render( + + + + + + + + + , + ); + await wait(); + }); + + test('User is able to select a contact', async () => { + const mock = [ + ...USER_JOINED_ORG_MOCK, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...DIRECT_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_DIRECT_CHAT_MOCK, + ...MESSAGE_SENT_TO_GROUP_CHAT_MOCK, + ...UserConnectionListMock, + ...MOCKS, + ]; + + render( + + + + + + + + + , + ); + + await wait(); + + expect(await screen.findByText('Messages')).toBeInTheDocument(); + const contactCards = await screen.findAllByTestId('chatContact'); + console.log(contactCards); + expect(contactCards[0]).toBeInTheDocument(); + act(() => { + fireEvent.click(contactCards[0]); + }); + }); + + test('Test create new direct chat', async () => { + const mock = [ + ...USER_JOINED_ORG_MOCK, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...DIRECT_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_DIRECT_CHAT_MOCK, + ...MESSAGE_SENT_TO_GROUP_CHAT_MOCK, + ...UserConnectionListMock, + ...MOCKS, + ]; + 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, + ...DIRECT_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_DIRECT_CHAT_MOCK, + ...MESSAGE_SENT_TO_GROUP_CHAT_MOCK, + ...UserConnectionListMock, + ...MOCKS, + ]; + 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, + ...DIRECT_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_DIRECT_CHAT_MOCK, + ...MESSAGE_SENT_TO_GROUP_CHAT_MOCK, + ...UserConnectionListMock, + ...MOCKS, + ]; + setItem('userId', '1'); + + render( + + + + + + + + + , + ); + + await wait(); + + const closeMenubtn = screen.getByTestId('closeMenu'); + expect(closeMenubtn).toBeInTheDocument(); + closeMenubtn.click(); + const openMenuBtn = screen.getByTestId('openMenu'); + expect(openMenuBtn).toBeInTheDocument(); + openMenuBtn.click(); + }); + + 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, + ...DIRECT_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_DIRECT_CHAT_MOCK, + ...MESSAGE_SENT_TO_GROUP_CHAT_MOCK, + ...UserConnectionListMock, + ...MOCKS, + ]; + resizeWindow(800); + render( + + + + + + + + + , + ); + await wait(); + expect(screen.getByText('My Organizations')).toBeInTheDocument(); + expect(screen.getByText('Talawa User Portal')).toBeInTheDocument(); + + const chatBtn = screen.getByTestId('chatBtn'); + + chatBtn.click(); + }); +}); diff --git a/src/screens/UserPortal/Chat/Chat.tsx b/src/screens/UserPortal/Chat/Chat.tsx new file mode 100644 index 0000000000..2cc14eab58 --- /dev/null +++ b/src/screens/UserPortal/Chat/Chat.tsx @@ -0,0 +1,288 @@ +import React, { useEffect, useState } from 'react'; +import { DIRECT_CHATS_LIST } from 'GraphQl/Queries/Queries'; +import { 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 { ReactComponent as NewChat } from 'assets/svgs/newChat.svg'; +import Accordion from 'react-bootstrap/Accordion'; +import styles from './Chat.module.css'; +import UserSidebar from 'components/UserPortal/UserSidebar/UserSidebar'; +import { GROUP_CHAT_LIST } from 'GraphQl/Queries/PlugInQueries'; +import CreateGroupChat from '../../../components/UserPortal/CreateGroupChat/CreateGroupChat'; +import CreateDirectChat from 'components/UserPortal/CreateDirectChat/CreateDirectChat'; + +interface InterfaceContactCardProps { + id: string; + title: string; + subtitle: string; + image: string; + selectedContact: string; + setSelectedContact: React.Dispatch>; + type: string; + setSelectedChatType: React.Dispatch>; +} + +export default function chat(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'chat', + }); + const { t: tCommon } = useTranslation('common'); + + const [hideDrawer, setHideDrawer] = useState(null); + + const handleResize = (): void => { + if (window.innerWidth <= 820) { + setHideDrawer(!hideDrawer); + } + }; + + useEffect(() => { + handleResize(); + window.addEventListener('resize', handleResize); + return () => { + window.removeEventListener('resize', handleResize); + }; + }, []); + + const [selectedContact, setSelectedContact] = useState(''); + const [contacts, setContacts] = useState([]); + const [groupChats, setGroupChats] = useState([]); + const [selectChatType, setSelectedChatType] = useState(''); + const { getItem } = useLocalStorage(); + const userId = getItem('userId'); + + const [createDirectChatModalisOpen, setCreateDirectChatModalisOpen] = + useState(false); + + function openCreateDirectChatModal(): void { + setCreateDirectChatModalisOpen(true); + } + + const toggleCreateDirectChatModal = /* istanbul ignore next */ (): void => + setCreateDirectChatModalisOpen(!createDirectChatModalisOpen); + + const [createGroupChatModalisOpen, setCreateGroupChatModalisOpen] = + useState(false); + + function openCreateGroupChatModal(): void { + setCreateGroupChatModalisOpen(true); + } + + const toggleCreateGroupChatModal = /* istanbul ignore next */ (): void => { + setCreateGroupChatModalisOpen(!createGroupChatModalisOpen); + }; + + const { + data: contactData, + loading: contactLoading, + refetch: contactRefetch, + } = useQuery(DIRECT_CHATS_LIST, { + variables: { + id: userId, + }, + }); + + const { + data: groupChatList, + loading: groupChatListLoading, + refetch: groupChatListRefetch, + } = useQuery(GROUP_CHAT_LIST, { + variables: { + id: userId, + }, + }); + + // 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); + // }; + + React.useEffect(() => { + if (contactData) { + setContacts(contactData.directChatsByUserID); + } + }, [contactData]); + + React.useEffect(() => { + if (groupChatList) { + setGroupChats(groupChatList.groupChatsByUserId); + } + }, [groupChatList]); + + return ( + <> + {hideDrawer ? ( + + ) : ( + + )} + +
    +
    +
    +
    +

    Messages

    + + + + + + + New Chat + + + New Group Chat + + + Starred Messages + + + +
    +
    + {contactLoading || groupChatListLoading ? ( +
    + Loading... +
    + ) : ( +
    + + {!!contacts.length && ( + + + DIRECT CHATS + + + {contacts.map((contact: any) => { + const cardProps: InterfaceContactCardProps = { + id: contact._id, + title: + contact.users[0]?._id === userId + ? `${contact.users[1]?.firstName} ${contact.users[1]?.lastName}` + : `${contact.users[0]?.firstName} ${contact.users[0]?.lastName}`, + subtitle: userId + ? contact.users[1]?.email + : contact.users[0]?.email, + image: userId + ? contact.users[1]?.image + : contact.users[0]?.image, + setSelectedContact, + selectedContact, + type: 'direct', + setSelectedChatType, + }; + return ( + + ); + })} + + + )} + {!!groupChats.length && ( + + + GROUP CHATS + + + {groupChats.map((chat: any) => { + const cardProps: InterfaceContactCardProps = { + id: chat._id, + title: chat.title, + subtitle: `${chat.users.length} ${chat.users.length > 1 ? 'members' : 'member'}`, + image: '', + setSelectedContact, + selectedContact, + type: 'group', + setSelectedChatType, + }; + return ( + + ); + })} + + + )} + +
    + )} +
    +
    +
    + +
    +
    +
    + {createGroupChatModalisOpen && ( + + )} + {createDirectChatModalisOpen && ( + + )} + + ); +} diff --git a/src/screens/UserPortal/Donate/Donate.module.css b/src/screens/UserPortal/Donate/Donate.module.css new file mode 100644 index 0000000000..4e21cb08d4 --- /dev/null +++ b/src/screens/UserPortal/Donate/Donate.module.css @@ -0,0 +1,93 @@ +.containerHeight { + height: 100vh; +} + +.mainContainer { + width: 50%; + flex-grow: 3; + padding: 1rem; + max-height: 100%; + overflow: auto; + display: flex; + flex-direction: column; + background-color: #f2f7ff; +} + +.inputContainer { + margin-top: 3rem; + flex: 1; + position: relative; +} +.input { + width: 70%; + position: relative; + box-shadow: 5px 5px 4px 0px #31bb6b1f; +} + +.box { + width: auto; + /* height: 200px; */ + background-color: white; + margin-top: 1rem; + padding: 20px; + border: 1px solid #dddddd; + border-radius: 10px; +} + +.heading { + font-size: 1.1rem; +} + +.donationInputContainer { + display: flex; + flex-direction: row; + margin-top: 20px; +} + +.donateBtn { + padding-inline: 1rem !important; +} + +.dropdown { + min-width: 6rem; +} + +.inputArea { + border: none; + outline: none; + background-color: #f1f3f6; +} + +.maxWidth { + width: 100%; +} + +.donateActions { + margin-top: 1rem; + width: 100%; + display: flex; + flex-direction: row-reverse; +} + +.donationsContainer { + padding-top: 4rem; + flex-grow: 1; + display: flex; + flex-direction: column; +} + +.donationCardsContainer { + display: flex; + flex-wrap: wrap; + gap: 1rem; + --bs-gutter-x: 0; +} + +.colorLight { + background-color: #f5f5f5; +} + +.content { + padding-top: 10px; + flex-grow: 1; +} diff --git a/src/screens/UserPortal/Donate/Donate.test.tsx b/src/screens/UserPortal/Donate/Donate.test.tsx new file mode 100644 index 0000000000..fc30ba7503 --- /dev/null +++ b/src/screens/UserPortal/Donate/Donate.test.tsx @@ -0,0 +1,283 @@ +import React from 'react'; +import { act, render, screen } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider } from 'react-i18next'; + +import { + ORGANIZATION_DONATION_CONNECTION_LIST, + USER_ORGANIZATION_CONNECTION, +} from 'GraphQl/Queries/Queries'; +import { BrowserRouter } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import Donate from './Donate'; +import userEvent from '@testing-library/user-event'; +import useLocalStorage from 'utils/useLocalstorage'; +import { DONATE_TO_ORGANIZATION } from 'GraphQl/Mutations/mutations'; + +const MOCKS = [ + { + request: { + query: ORGANIZATION_DONATION_CONNECTION_LIST, + variables: { + orgId: '', + }, + }, + result: { + data: { + getDonationByOrgIdConnection: [ + { + _id: '6391a15bcb738c181d238957', + nameOfUser: 'firstName lastName', + amount: 1, + userId: '6391a15bcb738c181d238952', + payPalId: 'payPalId', + updatedAt: '2024-04-03T16:43:01.514Z', + }, + ], + }, + }, + }, + { + request: { + query: USER_ORGANIZATION_CONNECTION, + variables: { + id: '', + }, + }, + result: { + data: { + organizationsConnection: [ + { + _id: '6401ff65ce8e8406b8f07af3', + image: '', + name: 'anyOrganization2', + description: 'desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + userRegistrationRequired: true, + createdAt: '12345678900', + creator: { firstName: 'John', lastName: 'Doe' }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: DONATE_TO_ORGANIZATION, + variables: { + userId: '123', + createDonationOrgId2: '', + payPalId: 'paypalId', + nameOfUser: 'name', + amount: 123, + nameOfOrg: 'anyOrganization2', + }, + }, + result: { + data: { + createDonation: [ + { + _id: '', + amount: 123, + nameOfUser: 'name', + nameOfOrg: 'anyOrganization2', + }, + ], + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: '' }), +})); + +describe('Testing Donate Screen [User Portal]', () => { + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // Deprecated + removeListener: jest.fn(), // Deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), + }); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + test('Screen should be rendered properly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + expect(screen.getByPlaceholderText('Search donations')).toBeInTheDocument(); + expect(screen.getByTestId('currency0')).toBeInTheDocument(); + expect(screen.getByPlaceholderText('Amount')).toBeInTheDocument(); + }); + + test('Currency is swtiched to USD', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('changeCurrencyBtn')); + + userEvent.click(screen.getByTestId('currency0')); + await wait(); + + expect(screen.getByTestId('currency0')).toBeInTheDocument(); + }); + + test('Currency is swtiched to INR', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('changeCurrencyBtn')); + + userEvent.click(screen.getByTestId('currency1')); + + await wait(); + }); + + test('Currency is swtiched to EUR', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('changeCurrencyBtn')); + + userEvent.click(screen.getByTestId('currency2')); + + await wait(); + }); + + test('Checking the existence of Donation Cards', async () => { + render( + + + + + + + + + , + ); + + await wait(); + expect(screen.getAllByTestId('donationCard')[0]).toBeInTheDocument(); + }); + + test('For Donation functionality', async () => { + const { setItem } = useLocalStorage(); + setItem('userId', '123'); + setItem('name', 'name'); + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.type(screen.getByTestId('donationAmount'), '123'); + userEvent.click(screen.getByTestId('donateBtn')); + await wait(); + }); +}); diff --git a/src/screens/UserPortal/Donate/Donate.tsx b/src/screens/UserPortal/Donate/Donate.tsx new file mode 100644 index 0000000000..4e39c4e1be --- /dev/null +++ b/src/screens/UserPortal/Donate/Donate.tsx @@ -0,0 +1,264 @@ +import React from 'react'; +import { useParams } from 'react-router-dom'; +import { Button, Dropdown, Form, InputGroup } from 'react-bootstrap'; +import { toast } from 'react-toastify'; +import { useQuery, useMutation } from '@apollo/client'; +import { Search } from '@mui/icons-material'; +import SendIcon from '@mui/icons-material/Send'; +import HourglassBottomIcon from '@mui/icons-material/HourglassBottom'; +import { useTranslation } from 'react-i18next'; + +import { + ORGANIZATION_DONATION_CONNECTION_LIST, + USER_ORGANIZATION_CONNECTION, +} from 'GraphQl/Queries/Queries'; +import { DONATE_TO_ORGANIZATION } from 'GraphQl/Mutations/mutations'; +import styles from './Donate.module.css'; +import DonationCard from 'components/UserPortal/DonationCard/DonationCard'; +import useLocalStorage from 'utils/useLocalstorage'; +import { errorHandler } from 'utils/errorHandler'; +import OrganizationSidebar from 'components/UserPortal/OrganizationSidebar/OrganizationSidebar'; +import PaginationList from 'components/PaginationList/PaginationList'; + +export interface InterfaceDonationCardProps { + id: string; + name: string; + amount: string; + userId: string; + payPalId: string; + updatedAt: string; +} + +export default function donate(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'donate', + }); + + const { getItem } = useLocalStorage(); + const userId = getItem('userId'); + const userName = getItem('name'); + + const { orgId: organizationId } = useParams(); + const [amount, setAmount] = React.useState(''); + const [organizationDetails, setOrganizationDetails]: any = React.useState({}); + const [donations, setDonations] = React.useState([]); + const [selectedCurrency, setSelectedCurrency] = React.useState(0); + const [page, setPage] = React.useState(0); + const [rowsPerPage, setRowsPerPage] = React.useState(5); + + const currencies = ['USD', 'INR', 'EUR']; + + const { + data: data2, + loading, + refetch, + } = useQuery(ORGANIZATION_DONATION_CONNECTION_LIST, { + variables: { orgId: organizationId }, + }); + + const { data } = useQuery(USER_ORGANIZATION_CONNECTION, { + variables: { id: organizationId }, + }); + + const [donate] = useMutation(DONATE_TO_ORGANIZATION); + + const navbarProps = { + currentPage: 'donate', + }; + + /* istanbul ignore next */ + const handleChangePage = ( + _event: React.MouseEvent | null, + newPage: number, + ): void => { + setPage(newPage); + }; + + /* istanbul ignore next */ + const handleChangeRowsPerPage = ( + event: React.ChangeEvent, + ): void => { + const newRowsPerPage = event.target.value; + + setRowsPerPage(parseInt(newRowsPerPage, 10)); + setPage(0); + }; + + React.useEffect(() => { + if (data) { + setOrganizationDetails(data.organizationsConnection[0]); + } + }, [data]); + + React.useEffect(() => { + if (data2) { + setDonations(data2.getDonationByOrgIdConnection); + } + }, [data2]); + + const donateToOrg = (): void => { + try { + donate({ + variables: { + userId, + createDonationOrgId2: organizationId, + payPalId: 'paypalId', + nameOfUser: userName, + amount: Number(amount), + nameOfOrg: organizationDetails.name, + }, + }); + refetch(); + toast.success(t(`success`)); + } catch (error: any) { + /* istanbul ignore next */ + errorHandler(t, error); + } + }; + + return ( + <> +
    +
    +

    {t(`donations`)}

    +
    +
    + + +
    +
    +
    +
    + {t('donateForThe')} {organizationDetails.name} +
    +
    + + + + + {currencies[selectedCurrency]} + + + + {currencies.map((currency, index) => { + return ( + setSelectedCurrency(index)} + data-testid={`currency${index}`} + > + {currency} + + ); + })} + + + { + setAmount(e.target.value); + }} + /> + +
    +
    + +
    +
    +
    +
    {t('yourPreviousDonations')}
    +
    +
    + {loading ? ( +
    + Loading... +
    + ) : ( + <> + {donations && donations.length > 0 ? ( + (rowsPerPage > 0 + ? donations.slice( + page * rowsPerPage, + page * rowsPerPage + rowsPerPage, + ) + : /* istanbul ignore next */ + donations + ).map((donation: any, index) => { + const cardProps: InterfaceDonationCardProps = { + name: donation.nameOfUser, + id: donation._id, + amount: donation.amount, + userId: donation.userId, + payPalId: donation.payPalId, + updatedAt: donation.updatedAt, + }; + return ( +
    + +
    + ); + }) + ) : ( + {t('nothingToShow')} + )} + + )} +
    + + + + + + +
    +
    +
    +
    + +
    + + ); +} diff --git a/src/screens/UserPortal/Events/Events.module.css b/src/screens/UserPortal/Events/Events.module.css new file mode 100644 index 0000000000..db80124201 --- /dev/null +++ b/src/screens/UserPortal/Events/Events.module.css @@ -0,0 +1,164 @@ +.borderNone { + border: none; +} + +.colorWhite { + color: white; +} + +.backgroundWhite { + background-color: white; +} + +.maxWidth { + max-width: 800px; +} + +.colorLight { + background-color: #f1f3f6; +} + +.mainContainer { + width: 50%; + flex-grow: 3; + padding: 20px; + max-height: 100%; + overflow: auto; +} + +.content { + height: fit-content; + min-height: calc(100% - 40px); +} +.selectType { + border-radius: 10px; +} +.dropdown__item { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} + +.gap { + gap: 20px; +} + +.paddingY { + padding: 30px 0px; +} + +.containerHeight { + height: 100vh; +} + +.colorPrimary { + background: #31bb6b; + color: white; +} + +.eventActionsContainer { + display: flex; + flex-direction: row; + gap: 15px; +} + +.datePicker { + border-radius: 10px; + height: 40px; + text-align: center; + background-color: #f2f2f2; + border: none; + width: 100%; +} + +.modalBody { + display: flex; + flex-direction: column; + gap: 10px; +} + +.switchContainer { + display: flex; + align-items: center; +} + +.switches { + display: flex; + flex-direction: row; + gap: 20px; + flex-wrap: wrap; + margin-top: 20px; +} +.titlemodal { + color: #707070; + font-weight: 600; + font-size: 20px; + margin-bottom: 20px; + padding-bottom: 5px; + border-bottom: 3px solid #31bb6b; + width: 65%; +} + +.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; +} + +.checkboxdiv { + display: flex; +} +.checkboxdiv > div { + width: 50%; +} + +.dispflex { + display: flex; + align-items: center; +} +.dispflex > input { + border: none; + box-shadow: none; + margin-top: 5px; +} + +.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/Events/Events.test.tsx b/src/screens/UserPortal/Events/Events.test.tsx new file mode 100644 index 0000000000..6de04ee172 --- /dev/null +++ b/src/screens/UserPortal/Events/Events.test.tsx @@ -0,0 +1,521 @@ +import React from 'react'; +import { act, fireEvent, render, screen } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider } from 'react-i18next'; + +import { ORGANIZATION_EVENTS_CONNECTION } from 'GraphQl/Queries/Queries'; +import { BrowserRouter } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import Events from './Events'; +import userEvent from '@testing-library/user-event'; +import { CREATE_EVENT_MUTATION } from 'GraphQl/Mutations/mutations'; +import { toast } from 'react-toastify'; +import dayjs from 'dayjs'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { ThemeProvider } from 'react-bootstrap'; +import { createTheme } from '@mui/material'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem, getItem } = useLocalStorage(); + +jest.mock('react-toastify', () => ({ + toast: { + error: jest.fn(), + info: jest.fn(), + success: jest.fn(), + }, +})); + +jest.mock('@mui/x-date-pickers/DatePicker', () => { + return { + DatePicker: jest.requireActual('@mui/x-date-pickers/DesktopDatePicker') + .DesktopDatePicker, + }; +}); + +jest.mock('@mui/x-date-pickers/TimePicker', () => { + return { + TimePicker: jest.requireActual('@mui/x-date-pickers/DesktopTimePicker') + .DesktopTimePicker, + }; +}); + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: '' }), +})); + +const theme = createTheme({ + palette: { + primary: { + main: '#31bb6b', + }, + }, +}); + +const MOCKS = [ + { + request: { + query: ORGANIZATION_EVENTS_CONNECTION, + variables: { + organization_id: '', + title_contains: '', + }, + }, + result: { + data: { + eventsByOrganizationConnection: [ + { + _id: '6404a267cc270739118e2349', + title: 'NewEvent', + description: 'sdadsasad', + startDate: '2023-03-05', + endDate: '2023-03-05', + location: 'NewLocation', + startTime: null, + endTime: null, + allDay: true, + recurring: false, + isPublic: true, + isRegisterable: false, + creator: { + _id: '63d649417ffe6e4d5174ea32', + firstName: 'Noble', + lastName: 'Mittal', + __typename: 'User', + }, + attendees: [ + { + _id: '63d649417ffe6e4d5174ea32', + __typename: 'User', + }, + { + _id: '63d6064458fce20ee25c3bf7', + __typename: 'User', + }, + ], + __typename: 'Event', + }, + { + _id: '6404e952c651df745358849d', + title: '1parti', + description: 'asddas', + startDate: '2023-03-06', + endDate: '2023-03-06', + location: 'das', + startTime: '00:40:00.000Z', + endTime: '02:40:00.000Z', + allDay: false, + recurring: false, + isPublic: true, + isRegisterable: true, + creator: { + _id: '63d649417ffe6e4d5174ea32', + firstName: 'Noble', + lastName: 'Mittal', + __typename: 'User', + }, + attendees: [ + { + _id: '63d649417ffe6e4d5174ea32', + __typename: 'User', + }, + { + _id: '63dd52bbe69f63814b0a5dd4', + __typename: 'User', + }, + { + _id: '63d6064458fce20ee25c3bf7', + __typename: 'User', + }, + ], + __typename: 'Event', + }, + ], + }, + }, + }, + { + request: { + query: ORGANIZATION_EVENTS_CONNECTION, + variables: { + organization_id: '', + title_contains: 'test', + }, + }, + result: { + data: { + eventsByOrganizationConnection: [ + { + _id: '6404a267cc270739118e2349', + title: 'NewEvent', + description: 'sdadsasad', + startDate: '2023-03-05', + endDate: '2023-03-05', + location: 'NewLocation', + startTime: null, + endTime: null, + allDay: true, + recurring: false, + isPublic: true, + isRegisterable: false, + creator: { + _id: '63d649417ffe6e4d5174ea32', + firstName: 'Noble', + lastName: 'Mittal', + __typename: 'User', + }, + attendees: [ + { + _id: '63d649417ffe6e4d5174ea32', + __typename: 'User', + }, + { + _id: '63d6064458fce20ee25c3bf7', + __typename: 'User', + }, + ], + __typename: 'Event', + }, + ], + }, + }, + }, + { + request: { + query: CREATE_EVENT_MUTATION, + variables: { + title: 'testEventTitle', + description: 'testEventDescription', + location: 'testEventLocation', + 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, + startTime: '08:00:00Z', + endTime: '10:00:00Z', + }, + }, + result: { + data: { + createEvent: { + _id: '2', + }, + }, + }, + }, + { + request: { + query: CREATE_EVENT_MUTATION, + variables: { + title: 'testEventTitle', + description: 'testEventDescription', + location: 'testEventLocation', + 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, + startTime: null, + endTime: null, + }, + }, + result: { + data: { + createEvent: { + _id: '1', + }, + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +describe('Testing Events Screen [User Portal]', () => { + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // Deprecated + removeListener: jest.fn(), // Deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), + }); + + test('Screen should be rendered properly', async () => { + render( + + + + + + + + + , + ); + setItem('SuperAdmin', true); // testing userRole as Superadmin + await wait(); + setItem('SuperAdmin', false); + setItem('AdminFor', ['123']); // testing userRole as Admin + await wait(); + }); + + test('Create event works as expected when event is not an all day event.', async () => { + render( + + + + + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('createEventModalBtn')); + + const randomEventTitle = 'testEventTitle'; + const randomEventDescription = 'testEventDescription'; + const randomEventLocation = 'testEventLocation'; + + userEvent.type(screen.getByTestId('eventTitleInput'), randomEventTitle); + userEvent.type( + screen.getByTestId('eventDescriptionInput'), + randomEventDescription, + ); + userEvent.type( + screen.getByTestId('eventLocationInput'), + randomEventLocation, + ); + + userEvent.click(screen.getByTestId('publicEventCheck')); + userEvent.click(screen.getByTestId('publicEventCheck')); + + userEvent.click(screen.getByTestId('registerableEventCheck')); + userEvent.click(screen.getByTestId('registerableEventCheck')); + + userEvent.click(screen.getByTestId('recurringEventCheck')); + userEvent.click(screen.getByTestId('recurringEventCheck')); + + userEvent.click(screen.getByTestId('recurringEventCheck')); + userEvent.click(screen.getByTestId('recurringEventCheck')); + + userEvent.click(screen.getByTestId('allDayEventCheck')); + + userEvent.click(screen.getByTestId('createEventBtn')); + + await wait(); + + expect(toast.success).toBeCalledWith( + 'Event created and posted successfully.', + ); + }); + + test('Create event works as expected when event is an all day event.', async () => { + render( + + + + + + + + + + + + + , + ); + await wait(); + + userEvent.click(screen.getByTestId('createEventModalBtn')); + + const randomEventTitle = 'testEventTitle'; + const randomEventDescription = 'testEventDescription'; + const randomEventLocation = 'testEventLocation'; + + userEvent.type(screen.getByTestId('eventTitleInput'), randomEventTitle); + userEvent.type( + screen.getByTestId('eventDescriptionInput'), + randomEventDescription, + ); + userEvent.type( + screen.getByTestId('eventLocationInput'), + randomEventLocation, + ); + + userEvent.click(screen.getByTestId('createEventBtn')); + + await wait(); + + expect(toast.success).toBeCalledWith( + 'Event created and posted successfully.', + ); + }); + + test('Switch to calendar view works as expected.', async () => { + render( + + + + + + + + + + + + + , + ); + + // await wait(); + + // userEvent.click(screen.getByTestId('modeChangeBtn')); + // userEvent.click(screen.getByTestId('modeBtn1')); + + await wait(); + const calenderView = 'Calendar View'; + + expect(screen.queryAllByText(calenderView)).not.toBeNull(); + expect(screen.getByText('Sun')).toBeInTheDocument(); + }); + + test('Testing DatePicker and TimePicker', async () => { + render( + + + + + + + + + + + + + , + ); + + 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')); + + expect(endDate).not.toBeNull(); + const endDateDatePicker = screen.getByLabelText('End Date'); + expect(startDate).not.toBeNull(); + const startDateDatePicker = screen.getByLabelText('Start Date'); + + fireEvent.change(startDateDatePicker, { + target: { value: startDate }, + }); + fireEvent.change(endDateDatePicker, { + target: { value: endDate }, + }); + + await wait(); + + expect(endDateDatePicker).toHaveValue(endDate); + expect(startDateDatePicker).toHaveValue(startDate); + + userEvent.click(screen.getByTestId('allDayEventCheck')); + + expect(endTime).not.toBeNull(); + const endTimePicker = screen.getByLabelText('End Time'); + expect(startTime).not.toBeNull(); + const startTimePicker = screen.getByLabelText('Start Time'); + + fireEvent.change(startTimePicker, { + target: { value: startTime }, + }); + fireEvent.change(endTimePicker, { + target: { value: endTime }, + }); + + await wait(); + expect(endTimePicker).toHaveValue(endTime); + expect(startTimePicker).toHaveValue(startTime); + }); + + test('EndDate null', async () => { + render( + + + + + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('createEventModalBtn')); + + const endDateDatePicker = screen.getByLabelText('End Date'); + const startDateDatePicker = screen.getByLabelText('Start Date'); + + fireEvent.change(startDateDatePicker, { + target: { value: null }, + }); + fireEvent.change(endDateDatePicker, { + target: { value: null }, + }); + + userEvent.click(screen.getByTestId('allDayEventCheck')); + + const endTimePicker = screen.getByLabelText('End Time'); + const startTimePicker = screen.getByLabelText('Start Time'); + + fireEvent.change(startTimePicker, { + target: { value: null }, + }); + fireEvent.change(endTimePicker, { + target: { value: null }, + }); + }); +}); diff --git a/src/screens/UserPortal/Events/Events.tsx b/src/screens/UserPortal/Events/Events.tsx new file mode 100644 index 0000000000..bf2de7e456 --- /dev/null +++ b/src/screens/UserPortal/Events/Events.tsx @@ -0,0 +1,348 @@ +import { useMutation, useQuery } from '@apollo/client'; +import { DatePicker, TimePicker } from '@mui/x-date-pickers'; +import { CREATE_EVENT_MUTATION } from 'GraphQl/Mutations/mutations'; +import { + ORGANIZATIONS_LIST, + ORGANIZATION_EVENTS_CONNECTION, +} from 'GraphQl/Queries/Queries'; +import EventCalendar from 'components/EventCalendar/EventCalendar'; +import EventHeader from 'components/EventCalendar/EventHeader'; +import type { Dayjs } from 'dayjs'; +import dayjs from 'dayjs'; +import type { ChangeEvent } from 'react'; +import React from 'react'; +import { Button, Form } from 'react-bootstrap'; +import Modal from 'react-bootstrap/Modal'; +import { useTranslation } from 'react-i18next'; +import { useParams } from 'react-router-dom'; +import { toast } from 'react-toastify'; +import { ViewType } from 'screens/OrganizationEvents/OrganizationEvents'; +import { errorHandler } from 'utils/errorHandler'; +import useLocalStorage from 'utils/useLocalstorage'; +import styles from './Events.module.css'; + +const timeToDayJs = (time: string): Dayjs => { + const dateTimeString = dayjs().format('YYYY-MM-DD') + ' ' + time; + return dayjs(dateTimeString, { format: 'YYYY-MM-DD HH:mm:ss' }); +}; + +export default function events(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'userEvents', + }); + const { t: tCommon } = useTranslation('common'); + + const { getItem } = useLocalStorage(); + + const [events, setEvents] = React.useState([]); + const [eventTitle, setEventTitle] = React.useState(''); + const [eventDescription, setEventDescription] = React.useState(''); + const [eventLocation, setEventLocation] = React.useState(''); + const [startDate, setStartDate] = React.useState(new Date()); + const [endDate, setEndDate] = React.useState(new Date()); + const [isPublic, setIsPublic] = React.useState(true); + const [isRegisterable, setIsRegisterable] = React.useState(true); + const [isRecurring, setIsRecurring] = React.useState(false); + const [isAllDay, setIsAllDay] = React.useState(true); + const [startTime, setStartTime] = React.useState('08:00:00'); + const [endTime, setEndTime] = React.useState('10:00:00'); + const [viewType, setViewType] = React.useState(ViewType.MONTH); + const [createEventModal, setCreateEventmodalisOpen] = React.useState(false); + const { orgId: organizationId } = useParams(); + + const { data, refetch } = useQuery(ORGANIZATION_EVENTS_CONNECTION, { + variables: { + organization_id: organizationId, + title_contains: '', + }, + }); + + const { data: orgData } = useQuery(ORGANIZATIONS_LIST, { + variables: { id: organizationId }, + }); + + const [create] = useMutation(CREATE_EVENT_MUTATION); + + const userId = getItem('id') as string; + + const superAdmin = getItem('SuperAdmin'); + const adminFor = getItem('AdminFor'); + const userRole = superAdmin + ? 'SUPERADMIN' + : adminFor?.length > 0 + ? 'ADMIN' + : 'USER'; + + const createEvent = async ( + e: ChangeEvent, + ): Promise => { + e.preventDefault(); + try { + const { data: createEventData } = await create({ + variables: { + title: eventTitle, + description: eventDescription, + isPublic, + recurring: isRecurring, + isRegisterable: isRegisterable, + organizationId, + startDate: dayjs(startDate).format('YYYY-MM-DD'), + endDate: dayjs(endDate).format('YYYY-MM-DD'), + allDay: isAllDay, + location: eventLocation, + startTime: !isAllDay ? startTime + 'Z' : null, + endTime: !isAllDay ? endTime + 'Z' : null, + }, + }); + + /* istanbul ignore next */ + if (createEventData) { + toast.success(t('eventCreated')); + refetch(); + setEventTitle(''); + setEventDescription(''); + setEventLocation(''); + setStartDate(new Date()); + setEndDate(new Date()); + setStartTime('08:00:00'); + setEndTime('10:00:00'); + } + setCreateEventmodalisOpen(false); + } catch (error: unknown) { + /* istanbul ignore next */ + errorHandler(t, error); + } + }; + + /* istanbul ignore next */ + const toggleCreateEventModal = (): void => + setCreateEventmodalisOpen(!createEventModal); + + const handleEventTitleChange = ( + event: React.ChangeEvent, + ): void => { + setEventTitle(event.target.value); + }; + + const handleEventLocationChange = ( + event: React.ChangeEvent, + ): void => { + setEventLocation(event.target.value); + }; + + const handleEventDescriptionChange = ( + event: React.ChangeEvent, + ): void => { + setEventDescription(event.target.value); + }; + + /* istanbul ignore next */ + React.useEffect(() => { + if (data) { + setEvents(data.eventsByOrganizationConnection); + } + }, [data]); + + /* istanbul ignore next */ + const showInviteModal = (): void => { + setCreateEventmodalisOpen(true); + }; + /* istanbul ignore next */ + const handleChangeView = (item: string | null): void => { + /*istanbul ignore next*/ + if (item) { + setViewType(item as ViewType); + } + }; + + return ( + <> +
    +
    +

    Events

    + +
    + +
    + + +

    {t('eventDetails')}

    + +
    + +
    + + + + + + +
    +
    + { + if (date) { + setStartDate(date?.toDate()); + setEndDate(date?.toDate()); + } + }} + data-testid="eventStartDate" + /> +
    +
    + { + if (date) { + setEndDate(date?.toDate()); + } + }} + minDate={dayjs(startDate)} + data-testid="eventEndDate" + /> +
    +
    +
    +
    + { + if (time) { + setStartTime(time?.format('HH:mm:ss')); + setEndTime(time?.format('HH:mm:ss')); + } + }} + disabled={isAllDay} + /> +
    +
    + { + if (time) { + setEndTime(time?.format('HH:mm:ss')); + } + }} + minTime={timeToDayJs(startTime)} + disabled={isAllDay} + /> +
    +
    +
    +
    + + setIsAllDay(!isAllDay)} + /> +
    +
    + + setIsRecurring(!isRecurring)} + /> +
    +
    +
    +
    + + setIsPublic(!isPublic)} + /> +
    +
    + + setIsRegisterable(!isRegisterable)} + /> +
    +
    + + +
    +
    +
    +
    + + ); +} diff --git a/src/screens/UserPortal/Organizations/Organizations.module.css b/src/screens/UserPortal/Organizations/Organizations.module.css new file mode 100644 index 0000000000..27262932d5 --- /dev/null +++ b/src/screens/UserPortal/Organizations/Organizations.module.css @@ -0,0 +1,145 @@ +.borderNone { + border: none; +} + +.colorWhite { + color: white; +} + +.colorLight { + background-color: #f5f5f5; +} + +.mainContainer { + max-height: 100%; + overflow: auto; +} + +.content { + height: fit-content; + min-height: calc(100% - 40px); +} + +.paddingY { + padding: 30px 0px; +} + +.containerHeight { + height: 100vh; + padding: 1rem 1.5rem 0 calc(300px + 1.5rem); +} + +.expand { + padding-left: 4rem; + animation: moveLeft 0.9s ease-in-out; +} + +.contract { + padding-left: calc(300px + 2rem + 1.5rem); + animation: moveRight 0.5s ease-in-out; +} + +.colorPrimary { + background: #31bb6b; +} + +.backgroundWhite { + background-color: white; +} + +.input { + flex: 1; + position: relative; + margin-right: 10px; +} + +.btnsContainer input { + outline: 1px solid var(--bs-gray-400); +} + +.collapseSidebarButton { + position: fixed; + height: 40px; + bottom: 0; + z-index: 9999; + width: calc(300px); + background-color: rgba(245, 245, 245, 0.7); + color: black; + border: none; + border-radius: 0px; +} + +.collapseSidebarButton:hover, +.opendrawer:hover { + opacity: 1; + color: black !important; +} +.opendrawer { + position: fixed; + display: flex; + align-items: center; + justify-content: center; + top: 0; + left: 0; + width: 40px; + height: 100vh; + z-index: 9999; + background-color: rgba(245, 245, 245); + border: none; + border-radius: 0px; + margin-right: 20px; + color: black; +} + +.opendrawer:hover { + transition: background-color 0.5s ease; + background-color: var(--bs-primary); +} +.collapseSidebarButton:hover { + transition: background-color 0.5s ease; + background-color: var(--bs-primary); +} + +@media screen and (max-width: 850px) { + .mainContainer { + width: 100%; + } +} + +@media (max-width: 1120px) { + .collapseSidebarButton { + width: calc(250px + 2rem); + } +} + +@media (max-height: 650px) { + .collapseSidebarButton { + width: 250px; + height: 20px; + } + .opendrawer { + width: 30px; + } +} + +/* For tablets */ +@media (max-width: 820px) { + .containerHeight { + height: 100vh; + padding: 2rem; + } + .opendrawer { + width: 25px; + } + + .contract, + .expand { + animation: none; + } + + .collapseSidebarButton { + width: 100%; + left: 0; + right: 0; + } +} diff --git a/src/screens/UserPortal/Organizations/Organizations.test.tsx b/src/screens/UserPortal/Organizations/Organizations.test.tsx new file mode 100644 index 0000000000..87d0997409 --- /dev/null +++ b/src/screens/UserPortal/Organizations/Organizations.test.tsx @@ -0,0 +1,511 @@ +import { MockedProvider } from '@apollo/react-testing'; +import { act, fireEvent, render, screen } from '@testing-library/react'; +import { I18nextProvider } from 'react-i18next'; + +import userEvent from '@testing-library/user-event'; +import { + USER_CREATED_ORGANIZATIONS, + USER_JOINED_ORGANIZATIONS, + USER_ORGANIZATION_CONNECTION, +} from 'GraphQl/Queries/Queries'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18nForTest from 'utils/i18nForTest'; +import useLocalStorage from 'utils/useLocalstorage'; +import Organizations from './Organizations'; +import React from 'react'; +const { getItem } = useLocalStorage(); + +const MOCKS = [ + { + request: { + query: USER_CREATED_ORGANIZATIONS, + variables: { + id: getItem('userId'), + }, + }, + result: { + data: { + users: [ + { + appUserProfile: { + createdOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + image: '', + name: 'anyOrganization1', + description: '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_ORGANIZATION_CONNECTION, + variables: { + filter: '', + }, + }, + result: { + data: { + organizationsConnection: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + image: '', + name: 'anyOrganization1', + description: '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: '6401ff65ce8e8406b8f07af3', + image: '', + name: 'anyOrganization2', + createdAt: '1234567890', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + description: 'desc', + 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: getItem('userId'), + }, + }, + result: { + data: { + users: [ + { + user: { + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + image: '', + name: 'anyOrganization1', + description: '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_ORGANIZATION_CONNECTION, + variables: { + filter: '2', + }, + }, + result: { + data: { + organizationsConnection: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af3', + image: '', + name: 'anyOrganization2', + description: 'desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + userRegistrationRequired: true, + createdAt: '1234567890', + creator: { __typename: 'User', firstName: 'John', lastName: 'Doe' }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + user: { + _id: '4567890fgvhbjn', + }, + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + ], + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const resizeWindow = (width: number): void => { + window.innerWidth = width; + fireEvent(window, new Event('resize')); +}; + +describe('Testing Organizations Screen [User Portal]', () => { + test('Screen should be rendered properly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + }); + + test('Search works properly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + const searchBtn = screen.getByTestId('searchBtn'); + userEvent.type(screen.getByTestId('searchInput'), '2{enter}'); + await wait(); + + expect(screen.queryByText('anyOrganization2')).toBeInTheDocument(); + + userEvent.clear(screen.getByTestId('searchInput')); + userEvent.click(searchBtn); + await wait(); + }); + + test('Mode is changed to joined organizations', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('modeChangeBtn')); + await wait(); + userEvent.click(screen.getByTestId('modeBtn1')); + await wait(); + + expect(screen.queryAllByText('joinedOrganization')).not.toBe([]); + }); + + test('Mode is changed to created organizations', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('modeChangeBtn')); + await wait(); + userEvent.click(screen.getByTestId('modeBtn2')); + await wait(); + + expect(screen.queryAllByText('createdOrganization')).not.toBe([]); + }); + + test('Join Now button render correctly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + // Assert "Join Now" button + const joinNowButtons = screen.getAllByTestId('joinBtn'); + expect(joinNowButtons.length).toBeGreaterThan(0); + }); + + test('Mode is changed to created organizations', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('modeChangeBtn')); + await wait(); + userEvent.click(screen.getByTestId('modeBtn2')); + await wait(); + + expect(screen.queryAllByText('createdOrganization')).not.toBe([]); + }); + + test('Testing Sidebar', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + const closeMenubtn = screen.getByTestId('closeMenu'); + expect(closeMenubtn).toBeInTheDocument(); + closeMenubtn.click(); + const openMenuBtn = screen.getByTestId('openMenu'); + expect(openMenuBtn).toBeInTheDocument(); + openMenuBtn.click(); + }); + + test('Testing sidebar when the screen size is less than or equal to 820px', async () => { + resizeWindow(800); + render( + + + + + + + + + , + ); + + await wait(); + expect(screen.getByText('My Organizations')).toBeInTheDocument(); + expect(screen.getByText('Talawa User Portal')).toBeInTheDocument(); + + const settingsBtn = screen.getByTestId('settingsBtn'); + + settingsBtn.click(); + }); +}); diff --git a/src/screens/UserPortal/Organizations/Organizations.tsx b/src/screens/UserPortal/Organizations/Organizations.tsx new file mode 100644 index 0000000000..433416387d --- /dev/null +++ b/src/screens/UserPortal/Organizations/Organizations.tsx @@ -0,0 +1,382 @@ +import { useQuery } from '@apollo/client'; +import { SearchOutlined } from '@mui/icons-material'; +import HourglassBottomIcon from '@mui/icons-material/HourglassBottom'; +import { + USER_CREATED_ORGANIZATIONS, + USER_JOINED_ORGANIZATIONS, + USER_ORGANIZATION_CONNECTION, +} from 'GraphQl/Queries/Queries'; +import PaginationList from 'components/PaginationList/PaginationList'; +import OrganizationCard from 'components/UserPortal/OrganizationCard/OrganizationCard'; +import UserSidebar from 'components/UserPortal/UserSidebar/UserSidebar'; +import React, { useEffect, useState } from 'react'; +import { Button, Dropdown, Form, InputGroup } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; +import useLocalStorage from 'utils/useLocalstorage'; +import styles from './Organizations.module.css'; +import ProfileDropdown from 'components/ProfileDropdown/ProfileDropdown'; + +const { getItem } = useLocalStorage(); + +interface InterfaceOrganizationCardProps { + 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; + }; + }[]; +} + +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; + }; + }[]; +} + +export default function organizations(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'userOrganizations', + }); + + const [hideDrawer, setHideDrawer] = useState(null); + + const handleResize = (): void => { + if (window.innerWidth <= 820) { + setHideDrawer(!hideDrawer); + } + }; + + useEffect(() => { + handleResize(); + window.addEventListener('resize', handleResize); + return () => { + window.removeEventListener('resize', handleResize); + }; + }, []); + + const [page, setPage] = React.useState(0); + const [rowsPerPage, setRowsPerPage] = React.useState(5); + const [organizations, setOrganizations] = React.useState([]); + const [filterName, setFilterName] = React.useState(''); + const [mode, setMode] = React.useState(0); + + const modes = [ + t('allOrganizations'), + t('joinedOrganizations'), + t('createdOrganizations'), + ]; + + const userId: string | null = getItem('userId'); + + const { + data, + refetch, + loading: loadingOrganizations, + } = useQuery(USER_ORGANIZATION_CONNECTION, { + variables: { filter: filterName }, + }); + + const { data: joinedOrganizationsData } = useQuery( + USER_JOINED_ORGANIZATIONS, + { + variables: { id: userId }, + }, + ); + + const { data: createdOrganizationsData } = useQuery( + USER_CREATED_ORGANIZATIONS, + { + variables: { id: userId }, + }, + ); + + /* istanbul ignore next */ + const handleChangePage = ( + _event: React.MouseEvent | null, + newPage: number, + ): void => { + setPage(newPage); + }; + + /* istanbul ignore next */ + const handleChangeRowsPerPage = ( + event: React.ChangeEvent, + ): void => { + const newRowsPerPage = event.target.value; + + setRowsPerPage(parseInt(newRowsPerPage, 10)); + setPage(0); + }; + + const handleSearch = (value: string): void => { + setFilterName(value); + + refetch({ + filter: value, + }); + }; + const handleSearchByEnter = ( + e: React.KeyboardEvent, + ): void => { + if (e.key === 'Enter') { + const { value } = e.target as HTMLInputElement; + handleSearch(value); + } + }; + const handleSearchByBtnClick = (): void => { + const value = + (document.getElementById('searchUserOrgs') as HTMLInputElement)?.value || + ''; + handleSearch(value); + }; + + /* istanbul ignore next */ + React.useEffect(() => { + if (data) { + const organizations = data.organizationsConnection.map( + (organization: InterfaceOrganization) => { + let membershipRequestStatus = ''; + if ( + organization.members.find( + (member: { _id: string }) => member._id === userId, + ) + ) + membershipRequestStatus = 'accepted'; + else if ( + organization.membershipRequests.find( + (request: { user: { _id: string } }) => + request.user._id === userId, + ) + ) + membershipRequestStatus = 'pending'; + return { ...organization, membershipRequestStatus }; + }, + ); + setOrganizations(organizations); + } + }, [data]); + + /* istanbul ignore next */ + React.useEffect(() => { + if (mode === 0) { + if (data) { + const organizations = data.organizationsConnection.map( + (organization: InterfaceOrganization) => { + let membershipRequestStatus = ''; + if ( + organization.members.find( + (member: { _id: string }) => member._id === userId, + ) + ) + membershipRequestStatus = 'accepted'; + else if ( + organization.membershipRequests.find( + (request: { user: { _id: string } }) => + request.user._id === userId, + ) + ) + membershipRequestStatus = 'pending'; + return { ...organization, membershipRequestStatus }; + }, + ); + setOrganizations(organizations); + } + } else if (mode === 1) { + if (joinedOrganizationsData && joinedOrganizationsData.users.length > 0) { + const organizations = + joinedOrganizationsData.users[0]?.user?.joinedOrganizations || []; + setOrganizations(organizations); + } + } else if (mode === 2) { + if ( + createdOrganizationsData && + createdOrganizationsData.users.length > 0 + ) { + const organizations = + createdOrganizationsData.users[0]?.appUserProfile + ?.createdOrganizations || []; + setOrganizations(organizations); + } + } + }, [mode, data, joinedOrganizationsData, createdOrganizationsData, userId]); + return ( + <> + {hideDrawer ? ( + + ) : ( + + )} + +
    +
    +
    + +
    +

    {t('selectOrganization')}

    +
    + + + + + + + + + {modes[mode]} + + + {modes.map((value, index) => { + return ( + setMode(index)} + > + {value} + + ); + })} + + +
    + +
    +
    + {loadingOrganizations ? ( +
    + Loading... +
    + ) : ( + <> + {' '} + {organizations && organizations.length > 0 ? ( + (rowsPerPage > 0 + ? organizations.slice( + page * rowsPerPage, + page * rowsPerPage + rowsPerPage, + ) + : /* istanbul ignore next */ + organizations + ).map((organization: InterfaceOrganization, index) => { + const cardProps: InterfaceOrganizationCardProps = { + name: organization.name, + image: organization.image, + id: organization._id, + description: organization.description, + admins: organization.admins, + members: organization.members, + address: organization.address, + membershipRequestStatus: + organization.membershipRequestStatus, + userRegistrationRequired: + organization.userRegistrationRequired, + membershipRequests: organization.membershipRequests, + }; + return ; + }) + ) : ( + {t('nothingToShow')} + )} + + )} +
    + + + + + + +
    +
    +
    +
    + + ); +} diff --git a/src/screens/UserPortal/People/People.module.css b/src/screens/UserPortal/People/People.module.css new file mode 100644 index 0000000000..840be105f7 --- /dev/null +++ b/src/screens/UserPortal/People/People.module.css @@ -0,0 +1,89 @@ +.borderNone { + border: none; +} +.borderBox { + border: 1px solid #dddddd; +} + +.borderRounded5 { + border-radius: 5px; +} + +.borderRounded8 { + border-radius: 8px; +} + +.borderRounded24 { + border-radius: 24px; +} + +.topRadius { + border-top-left-radius: 24px; + border-top-right-radius: 24px; +} + +.bottomRadius { + border-bottom-left-radius: 24px; + border-bottom-right-radius: 24px; +} + +.shadow { + box-shadow: 5px 5px 4px 0px #31bb6b1f; +} + +.colorWhite { + color: white; +} + +.colorGreen { + color: #31bb6b; +} + +.backgroundWhite { + background-color: white; +} + +.maxWidth { + max-width: 600px; +} + +.colorLight { + background-color: #f5f5f5; +} + +.mainContainer { + width: 50%; + flex-grow: 3; + padding: 40px; + max-height: 100%; + overflow: auto; +} + +.content { + height: fit-content; + min-height: calc(100% - 40px); +} + +.gap { + gap: 20px; +} + +.containerHeight { + height: 100vh; +} + +.colorPrimary { + background: #31bb6b; +} + +.greenBorder { + border: 1px solid #31bb6b; +} + +.semiBold { + font-weight: 500; +} + +.placeholderColor::placeholder { + color: #737373; +} diff --git a/src/screens/UserPortal/People/People.test.tsx b/src/screens/UserPortal/People/People.test.tsx new file mode 100644 index 0000000000..a233c20015 --- /dev/null +++ b/src/screens/UserPortal/People/People.test.tsx @@ -0,0 +1,225 @@ +import React from 'react'; +import { act, render, screen } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider } from 'react-i18next'; +import { + ORGANIZATIONS_MEMBER_CONNECTION_LIST, + ORGANIZATION_ADMINS_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 { StaticMockLink } from 'utils/StaticMockLink'; +import People from './People'; +import userEvent from '@testing-library/user-event'; + +const MOCKS = [ + { + request: { + query: ORGANIZATIONS_MEMBER_CONNECTION_LIST, + variables: { + orgId: '', + firstName_contains: '', + }, + }, + result: { + data: { + organizationsMemberConnection: { + edges: [ + { + _id: '64001660a711c62d5b4076a2', + firstName: 'Noble', + lastName: 'Mittal', + image: null, + email: 'noble@gmail.com', + createdAt: '2023-03-02T03:22:08.101Z', + }, + { + _id: '64001660a711c62d5b4076a3', + firstName: 'Noble', + lastName: 'Mittal', + image: 'mockImage', + email: 'noble@gmail.com', + createdAt: '2023-03-02T03:22:08.101Z', + }, + ], + }, + }, + }, + }, + { + request: { + query: ORGANIZATION_ADMINS_LIST, + variables: { + id: '', + }, + }, + result: { + data: { + organizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + admins: [ + { + _id: '64001660a711c62d5b4076a2', + firstName: 'Noble', + lastName: 'Admin', + image: null, + email: 'noble@gmail.com', + createdAt: '2023-03-02T03:22:08.101Z', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: ORGANIZATIONS_MEMBER_CONNECTION_LIST, + variables: { + orgId: '', + firstName_contains: 'j', + }, + }, + result: { + data: { + organizationsMemberConnection: { + edges: [ + { + _id: '64001660a711c62d5b4076a2', + firstName: 'John', + lastName: 'Cena', + image: null, + email: 'john@gmail.com', + createdAt: '2023-03-02T03:22:08.101Z', + }, + ], + }, + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: '' }), +})); + +describe('Testing People Screen [User Portal]', () => { + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // Deprecated + removeListener: jest.fn(), // Deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), + }); + + test('Screen should be rendered properly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + expect(screen.queryAllByText('Noble Mittal')).not.toBe([]); + }); + + test('Search works properly by pressing enter', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.type(screen.getByTestId('searchInput'), 'j{enter}'); + await wait(); + + expect(screen.queryByText('John Cena')).toBeInTheDocument(); + expect(screen.queryByText('Noble Mittal')).not.toBeInTheDocument(); + }); + + test('Search works properly by clicking search Btn', async () => { + render( + + + + + + + + + , + ); + + await wait(); + const searchBtn = screen.getByTestId('searchBtn'); + userEvent.type(screen.getByTestId('searchInput'), ''); + userEvent.click(searchBtn); + await wait(); + userEvent.type(screen.getByTestId('searchInput'), 'j'); + userEvent.click(searchBtn); + await wait(); + + expect(screen.queryByText('John Cena')).toBeInTheDocument(); + expect(screen.queryByText('Noble Mittal')).not.toBeInTheDocument(); + }); + + test('Mode is changed to Admins', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('modeChangeBtn')); + await wait(); + userEvent.click(screen.getByTestId('modeBtn1')); + await wait(); + + expect(screen.queryByText('Noble Admin')).toBeInTheDocument(); + expect(screen.queryByText('Noble Mittal')).not.toBeInTheDocument(); + }); +}); diff --git a/src/screens/UserPortal/People/People.tsx b/src/screens/UserPortal/People/People.tsx new file mode 100644 index 0000000000..c8f373f72d --- /dev/null +++ b/src/screens/UserPortal/People/People.tsx @@ -0,0 +1,245 @@ +import React from 'react'; +import PeopleCard from 'components/UserPortal/PeopleCard/PeopleCard'; +import { Dropdown, Form, InputGroup } from 'react-bootstrap'; +import PaginationList from 'components/PaginationList/PaginationList'; +import { + ORGANIZATIONS_MEMBER_CONNECTION_LIST, + ORGANIZATION_ADMINS_LIST, +} from 'GraphQl/Queries/Queries'; +import { useQuery } from '@apollo/client'; +import { FilterAltOutlined, SearchOutlined } from '@mui/icons-material'; +import styles from './People.module.css'; +import { useTranslation } from 'react-i18next'; +import HourglassBottomIcon from '@mui/icons-material/HourglassBottom'; +import { useParams } from 'react-router-dom'; + +interface InterfaceOrganizationCardProps { + id: string; + name: string; + image: string; + email: string; + role: string; + sno: string; +} + +interface InterfaceMember { + firstName: string; + lastName: string; + image: string; + _id: string; + email: string; + userType: string; +} + +export default function people(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'userOrganizations', + }); + const { t: tCommon } = useTranslation('common'); + + const [page, setPage] = React.useState(0); + const [rowsPerPage, setRowsPerPage] = React.useState(5); + const [members, setMembers] = React.useState([]); + const [mode, setMode] = React.useState(0); + + const { orgId: organizationId } = useParams(); + + const modes = ['All Members', 'Admins']; + + const { data, loading, refetch } = useQuery( + ORGANIZATIONS_MEMBER_CONNECTION_LIST, + { + variables: { + orgId: organizationId, + firstName_contains: '', + }, + }, + ); + + const { data: data2 } = useQuery(ORGANIZATION_ADMINS_LIST, { + variables: { id: organizationId }, + }); + + /* istanbul ignore next */ + const handleChangePage = ( + _event: React.MouseEvent | null, + newPage: number, + ): void => { + setPage(newPage); + }; + + /* istanbul ignore next */ + const handleChangeRowsPerPage = ( + event: React.ChangeEvent, + ): void => { + const newRowsPerPage = event.target.value; + + setRowsPerPage(parseInt(newRowsPerPage, 10)); + setPage(0); + }; + + const handleSearch = (newFilter: string): void => { + refetch({ + firstName_contains: newFilter, + }); + }; + + const handleSearchByEnter = ( + e: React.KeyboardEvent, + ): void => { + if (e.key === 'Enter') { + const { value } = e.currentTarget; + handleSearch(value); + } + }; + + const handleSearchByBtnClick = (): void => { + const inputValue = + (document.getElementById('searchPeople') as HTMLInputElement)?.value || + ''; + handleSearch(inputValue); + }; + + React.useEffect(() => { + if (data) { + setMembers(data.organizationsMemberConnection.edges); + console.log(data); + } + }, [data]); + + /* istanbul ignore next */ + React.useEffect(() => { + if (mode == 0) { + if (data) { + setMembers(data.organizationsMemberConnection.edges); + } + } else if (mode == 1) { + if (data2) { + setMembers(data2.organizations[0].admins); + } + } + }, [mode]); + + return ( + <> +
    +
    +

    People

    +
    + + + + + + + + + + {tCommon('filter').toUpperCase()} + + + {modes.map((value, index) => { + return ( + setMode(index)} + > + {value} + + ); + })} + + +
    +
    +
    + + S.No + Avatar + + {/* Avatar */} + Name + Email + Role +
    + +
    + {loading ? ( +
    + Loading... +
    + ) : ( + <> + {members && members.length > 0 ? ( + (rowsPerPage > 0 + ? members.slice( + page * rowsPerPage, + page * rowsPerPage + rowsPerPage, + ) + : /* istanbul ignore next */ + members + ).map((member: InterfaceMember, index) => { + const name = `${member.firstName} ${member.lastName}`; + + const cardProps: InterfaceOrganizationCardProps = { + name, + image: member.image, + id: member._id, + email: member.email, + role: member.userType, + sno: (index + 1).toString(), + }; + return ; + }) + ) : ( + {t('nothingToShow')} + )} + + )} +
    + + + + + + +
    +
    +
    + {/* */} +
    + + ); +} diff --git a/src/screens/UserPortal/Posts/Posts.module.css b/src/screens/UserPortal/Posts/Posts.module.css new file mode 100644 index 0000000000..fc0263833e --- /dev/null +++ b/src/screens/UserPortal/Posts/Posts.module.css @@ -0,0 +1,191 @@ +.borderNone { + border: none; +} + +.colorWhite { + color: white; +} + +.colorLight { + background-color: #f5f5f5; +} + +.mainContainer { + width: 50%; + flex-grow: 3; + padding: 1rem; + max-height: 100%; + overflow-y: auto; + overflow-x: hidden; + background-color: #f2f7ff; +} + +.containerHeight { + height: 100vh; +} + +.link { + text-decoration: none !important; + color: black; +} + +.postInputContainer { + margin-top: 0.5rem; + margin-bottom: 1rem; +} + +.maxWidth { + width: 100%; + /* min-width: 3rem; */ + /* padding: 0; */ +} + +.inputArea { + border: none; + outline: none; + background-color: #f1f3f6; +} + +.postActionContainer { + display: flex; + flex-direction: row; + justify-content: space-between; + gap: 10px; +} + +.postActionBtn { + background-color: white; + border: none; + color: black; +} + +.postActionBtn:hover { + background-color: ghostwhite; + border: none; + color: black; +} + +.postInput { + resize: none; + border: none; + outline: none; + box-shadow: none; + background-color: white; + margin-bottom: 10px; +} + +.postInput:focus { + box-shadow: none; +} + +.postContainer { + width: auto; + background-color: white; + margin-top: 1rem; + padding: 1rem; + border: 1px solid #dddddd; + border-radius: 10px; +} + +.heading { + font-size: 1.1rem; +} + +.pinnedPostsCardsContainer { + overflow-x: scroll; + display: flex; + gap: 1rem; + --bs-gutter-x: 0; +} + +.postsCardsContainer { + /* display: flex; + flex-wrap: wrap; + gap: 1rem; + --bs-gutter-x: 0; */ +} + +.userImage { + display: flex; + width: 50px; + height: 50px; + margin-left: 1rem; + align-items: center; + justify-content: center; + overflow: hidden; + border-radius: 50%; + position: relative; + border: 2px solid #31bb6b; +} + +.userImage img { + position: absolute; + top: 0; + left: 0; + width: 100%; + scale: 1.5; +} + +.startPostBtn { + width: 100%; + border-radius: 25px; + background-color: transparent; + /* border: 1px solid #acacac; */ + box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px; + outline: none; + border: none; + color: #000; + font-weight: 900; +} + +.startPostBtn:hover { + background-color: #00000010; + border: 0; + color: #000 !important; +} + +.icons { + width: 25px; +} + +.icons svg { + stroke: #000; +} + +.icons.dark { + cursor: pointer; + border: none; + outline: none; + background-color: transparent; +} + +.icons.dark svg { + stroke: #000; +} + +.iconLabel { + margin: 0; + color: #000; + font-weight: 900; +} + +.uploadLink { + text-align: center; + width: min-content; + padding: 8px 4px; + border-radius: 4px; + cursor: pointer; +} + +.uploadLink:hover { + background-color: #00000010; +} + +.modal { + width: 100dvw; + margin: 0 auto; +} + +.imageInput { + display: none; +} diff --git a/src/screens/UserPortal/Posts/Posts.test.tsx b/src/screens/UserPortal/Posts/Posts.test.tsx new file mode 100644 index 0000000000..da499403ea --- /dev/null +++ b/src/screens/UserPortal/Posts/Posts.test.tsx @@ -0,0 +1,390 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import type { RenderResult } from '@testing-library/react'; +import { act, render, screen, waitFor, within } from '@testing-library/react'; +import { I18nextProvider } from 'react-i18next'; +import userEvent from '@testing-library/user-event'; +import { + ORGANIZATION_ADVERTISEMENT_LIST, + ORGANIZATION_POST_LIST, +} from 'GraphQl/Queries/Queries'; +import { Provider } from 'react-redux'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18nForTest from 'utils/i18nForTest'; +import Home from './Posts'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem } = useLocalStorage(); + +jest.mock('react-toastify', () => ({ + toast: { + error: jest.fn(), + info: jest.fn(), + success: jest.fn(), + }, +})); + +const MOCKS = [ + { + request: { + query: ORGANIZATION_POST_LIST, + variables: { + id: 'orgId', + first: 10, + }, + }, + result: { + data: { + organizations: [ + { + posts: { + edges: [ + { + node: { + _id: '6411e53835d7ba2344a78e21', + title: 'post one', + text: 'This is the first post', + imageUrl: null, + videoUrl: null, + createdAt: '2024-03-03T09:26:56.524+00:00', + creator: { + _id: '640d98d9eb6a743d75341067', + firstName: 'Glen', + lastName: 'Dsza', + email: 'glendsza@gmail.com', + }, + likeCount: 0, + commentCount: 0, + comments: [], + pinned: true, + likedBy: [], + }, + cursor: '6411e53835d7ba2344a78e21', + }, + { + node: { + _id: '6411e54835d7ba2344a78e29', + title: 'post two', + text: 'This is the post two', + imageUrl: null, + videoUrl: null, + createdAt: '2024-03-03T09:26:56.524+00:00', + creator: { + _id: '640d98d9eb6a743d75341067', + firstName: 'Glen', + lastName: 'Dsza', + email: 'glendsza@gmail.com', + }, + likeCount: 2, + commentCount: 1, + pinned: false, + likedBy: [ + { + _id: '640d98d9eb6a743d75341067', + firstName: 'Glen', + lastName: 'Dsza', + }, + { + _id: '640d98d9eb6a743d75341068', + firstName: 'Glen2', + lastName: 'Dsza2', + }, + ], + comments: [ + { + _id: '6411e54835d7ba2344a78e29', + creator: { + _id: '640d98d9eb6a743d75341067', + firstName: 'Glen', + lastName: 'Dsza', + email: 'glendsza@gmail.com', + }, + likeCount: 2, + likedBy: [ + { + _id: '640d98d9eb6a743d75341067', + firstName: 'Glen', + lastName: 'Dsza', + }, + { + _id: '640d98d9eb6a743d75341068', + firstName: 'Glen2', + lastName: 'Dsza2', + }, + ], + text: 'This is the post two', + createdAt: '2024-03-03T09:26:56.524+00:00', + }, + ], + }, + cursor: '6411e54835d7ba2344a78e29', + }, + ], + pageInfo: { + startCursor: '6411e53835d7ba2344a78e21', + endCursor: '6411e54835d7ba2344a78e31', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 2, + }, + }, + ], + }, + }, + }, + { + request: { + query: ORGANIZATION_ADVERTISEMENT_LIST, + variables: { id: 'orgId', first: 6 }, + }, + result: { + data: { + organizations: [ + { + _id: 'orgId', + advertisements: { + edges: [ + { + node: { + _id: '1234', + name: 'Ad 1', + type: 'Type 1', + organization: { + _id: 'orgId', + }, + mediaUrl: 'Link 1', + endDate: '2024-12-31', + startDate: '2022-01-01', + }, + cursor: '1234', + }, + { + node: { + _id: '2345', + name: 'Ad 2', + type: 'Type 1', + organization: { + _id: 'orgId', + }, + mediaUrl: 'Link 2', + endDate: '2024-09-31', + startDate: '2023-04-01', + }, + cursor: '1234', + }, + { + node: { + _id: '3456', + name: 'name3', + type: 'Type 2', + organization: { + _id: 'orgId', + }, + mediaUrl: 'link3', + startDate: '2023-01-30', + endDate: '2023-12-31', + }, + cursor: '1234', + }, + { + node: { + _id: '4567', + name: 'name4', + type: 'Type 2', + organization: { + _id: 'orgId1', + }, + mediaUrl: 'link4', + startDate: '2023-01-30', + endDate: '2023-12-01', + }, + cursor: '1234', + }, + ], + pageInfo: { + startCursor: '6411e53835d7ba2344a78e21', + endCursor: '6411e54835d7ba2344a78e31', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 2, + }, + }, + ], + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); + +afterEach(() => { + localStorage.clear(); +}); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const renderHomeScreen = (): RenderResult => + render( + + + + + + } /> + + + + + , + ); + +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(), + })), +}); + +describe('Testing Home Screen: User Portal', () => { + beforeAll(() => { + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: 'orgId' }), + })); + }); + + afterAll(() => { + jest.clearAllMocks(); + }); + + test('Check if HomeScreen renders properly', async () => { + renderHomeScreen(); + + await wait(); + const startPostBtn = await screen.findByTestId('postBtn'); + expect(startPostBtn).toBeInTheDocument(); + }); + + test('StartPostModal should render on click of StartPost btn', async () => { + renderHomeScreen(); + + await wait(); + const startPostBtn = await screen.findByTestId('postBtn'); + expect(startPostBtn).toBeInTheDocument(); + + userEvent.click(startPostBtn); + const startPostModal = screen.getByTestId('startPostModal'); + expect(startPostModal).toBeInTheDocument(); + }); + + test('StartPostModal should close on clicking the close button', async () => { + renderHomeScreen(); + + await wait(); + userEvent.upload( + screen.getByTestId('postImageInput'), + new File(['image content'], 'image.png', { type: 'image/png' }), + ); + await wait(); + + const startPostBtn = await screen.findByTestId('postBtn'); + expect(startPostBtn).toBeInTheDocument(); + + userEvent.click(startPostBtn); + const startPostModal = screen.getByTestId('startPostModal'); + expect(startPostModal).toBeInTheDocument(); + + userEvent.type(screen.getByTestId('postInput'), 'some content'); + + // Check that the content and image have been added + expect(screen.getByTestId('postInput')).toHaveValue('some content'); + await screen.findByAltText('Post Image Preview'); + expect(screen.getByAltText('Post Image Preview')).toBeInTheDocument(); + + const closeButton = within(startPostModal).getByRole('button', { + name: /close/i, + }); + userEvent.click(closeButton); + + const closedModalText = screen.queryByText(/somethingOnYourMind/i); + expect(closedModalText).not.toBeInTheDocument(); + + expect(screen.getByTestId('postInput')).toHaveValue(''); + expect(screen.getByTestId('postImageInput')).toHaveValue(''); + }); + + test('Check whether Posts render in PostCard', async () => { + setItem('userId', '640d98d9eb6a743d75341067'); + renderHomeScreen(); + await wait(); + + const postCardContainers = screen.findAllByTestId('postCardContainer'); + expect(postCardContainers).not.toBeNull(); + + expect(screen.queryAllByText('post one')[0]).toBeInTheDocument(); + expect( + screen.queryAllByText('This is the first post')[0], + ).toBeInTheDocument(); + + expect(screen.queryByText('post two')).toBeInTheDocument(); + expect(screen.queryByText('This is the post two')).toBeInTheDocument(); + }); + + test('Checking if refetch works after deleting this post', async () => { + setItem('userId', '640d98d9eb6a743d75341067'); + renderHomeScreen(); + await wait(); + + userEvent.click(screen.getAllByTestId('dropdown')[1]); + userEvent.click(screen.getByTestId('deletePost')); + }); +}); + +describe('HomeScreen with invalid orgId', () => { + test('Redirect to /user when organizationId is falsy', async () => { + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: undefined }), + })); + render( + + + + + + } /> + } + /> + + + + + , + ); + + // Wait for the navigation to occur + await waitFor(() => { + const homeEl = screen.getByTestId('homeEl'); + expect(homeEl).toBeInTheDocument(); + }); + }); +}); diff --git a/src/screens/UserPortal/Posts/Posts.tsx b/src/screens/UserPortal/Posts/Posts.tsx new file mode 100644 index 0000000000..e3d3d8556c --- /dev/null +++ b/src/screens/UserPortal/Posts/Posts.tsx @@ -0,0 +1,387 @@ +import { useQuery } from '@apollo/client'; +import HourglassBottomIcon from '@mui/icons-material/HourglassBottom'; +import SendIcon from '@mui/icons-material/Send'; +import { + ORGANIZATION_ADVERTISEMENT_LIST, + ORGANIZATION_POST_LIST, + USER_DETAILS, +} from 'GraphQl/Queries/Queries'; +import PostCard from 'components/UserPortal/PostCard/PostCard'; +import type { + InterfacePostCard, + InterfaceQueryOrganizationAdvertisementListItem, + InterfaceQueryUserListItem, +} from 'utils/interfaces'; +import PromotedPost from 'components/UserPortal/PromotedPost/PromotedPost'; +import StartPostModal from 'components/UserPortal/StartPostModal/StartPostModal'; +import React, { useEffect, useState } from 'react'; +import { Button, Col, Form, Row } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; + +import { Navigate, useParams } from 'react-router-dom'; +import useLocalStorage from 'utils/useLocalstorage'; +import styles from './Posts.module.css'; +import convertToBase64 from 'utils/convertToBase64'; +import Carousel from 'react-multi-carousel'; +import 'react-multi-carousel/lib/styles.css'; + +const responsive = { + superLargeDesktop: { + breakpoint: { max: 4000, min: 3000 }, + items: 5, + }, + desktop: { + breakpoint: { max: 3000, min: 1024 }, + items: 3, + }, + tablet: { + breakpoint: { max: 1024, min: 600 }, + items: 2, + }, + mobile: { + breakpoint: { max: 600, min: 0 }, + items: 1, + }, +}; + +type Ad = { + _id: string; + name: string; + type: 'BANNER' | 'MENU' | 'POPUP'; + mediaUrl: string; + endDate: string; // Assuming it's a string in the format 'yyyy-MM-dd' + startDate: string; // Assuming it's a string in the format 'yyyy-MM-dd' +}; +interface InterfaceAdContent { + _id: string; + name: string; + type: string; + organization: { + _id: string; + }; + mediaUrl: string; + endDate: string; + startDate: string; + + comments: InterfacePostComments; + likes: InterfacePostLikes; +} + +type AdvertisementsConnection = { + edges: { + node: InterfaceAdContent; + }[]; +}; + +type InterfacePostComments = { + creator: { + _id: string; + firstName: string; + lastName: string; + email: string; + }; + likeCount: number; + likedBy: { + id: string; + }[]; + text: string; +}[]; + +type InterfacePostLikes = { + firstName: string; + lastName: string; + id: string; +}[]; + +type InterfacePostNode = { + commentCount: number; + createdAt: string; + creator: { + email: string; + firstName: string; + lastName: string; + _id: string; + }; + imageUrl: string | null; + likeCount: number; + likedBy: { + _id: string; + firstName: string; + lastName: string; + }[]; + pinned: boolean; + text: string; + title: string; + videoUrl: string | null; + _id: string; + + comments: InterfacePostComments; + likes: InterfacePostLikes; +}; + +export default function home(): JSX.Element { + const { t } = useTranslation('translation', { keyPrefix: 'home' }); + const { t: tCommon } = useTranslation('common'); + const { getItem } = useLocalStorage(); + const [posts, setPosts] = useState([]); + const [pinnedPosts, setPinnedPosts] = useState([]); + + const [showModal, setShowModal] = useState(false); + const [postImg, setPostImg] = useState(''); + const { orgId } = useParams(); + + if (!orgId) { + return ; + } + + const { + data: promotedPostsData, + }: { + data?: { + organizations: InterfaceQueryOrganizationAdvertisementListItem[]; + }; + refetch: () => void; + } = useQuery(ORGANIZATION_ADVERTISEMENT_LIST, { + variables: { + id: orgId, + first: 6, + }, + }); + const { + data, + refetch, + loading: loadingPosts, + } = useQuery(ORGANIZATION_POST_LIST, { + variables: { id: orgId, first: 10 }, + }); + + const [adContent, setAdContent] = useState([]); + const userId: string | null = getItem('userId'); + + const { data: userData } = useQuery(USER_DETAILS, { + variables: { id: userId }, + }); + + const user: InterfaceQueryUserListItem | undefined = userData?.user; + + useEffect(() => { + if (data) { + setPosts(data.organizations[0].posts.edges); + } + }, [data]); + + useEffect(() => { + if (promotedPostsData && promotedPostsData.organizations) { + const ads: Ad[] = + promotedPostsData.organizations[0].advertisements?.edges.map( + (edge) => edge.node, + ) || []; + + setAdContent(ads); + } + }, [promotedPostsData]); + + useEffect(() => { + setPinnedPosts( + posts.filter(({ node }: { node: InterfacePostNode }) => { + return node.pinned; + }), + ); + }, [posts]); + + const getCardProps = (node: InterfacePostNode): InterfacePostCard => { + const { + creator, + _id, + imageUrl, + videoUrl, + title, + text, + likeCount, + commentCount, + likedBy, + 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 date = new Date(node.createdAt); + const formattedDate = new Intl.DateTimeFormat('en-US', { + year: 'numeric', + month: 'short', + day: 'numeric', + }).format(date); + + const cardProps: InterfacePostCard = { + id: _id, + creator: { + id: creator._id, + firstName: creator.firstName, + lastName: creator.lastName, + email: creator.email, + }, + postedAt: formattedDate, + image: imageUrl, + video: videoUrl, + title, + text, + likeCount, + commentCount, + comments: postComments, + likedBy: allLikes, + fetchPosts: () => refetch(), + }; + + return cardProps; + }; + + const handlePostButtonClick = (): void => { + setShowModal(true); + }; + + const handleModalClose = (): void => { + setShowModal(false); + }; + + return ( + <> +
    +
    +

    {t('posts')}

    +
    +
    {t('startPost')}
    +
    + + + , + ): Promise => { + setPostImg(''); + const target = e.target as HTMLInputElement; + const file = target.files && target.files[0]; + const base64file = file && (await convertToBase64(file)); + setPostImg(base64file); + }} + /> + + +
    +
    + +
    +
    +
    +

    {t('feed')}

    + {pinnedPosts.length > 0 && ( + + {pinnedPosts.map(({ node }: { node: InterfacePostNode }) => { + const cardProps = getCardProps(node); + return ; + })} + + )} +
    + + {adContent.length > 0 && ( +
    + {adContent.map((post: Ad) => ( + + ))} +
    + )} +

    {t(`yourFeed`)}

    +
    + {loadingPosts ? ( +
    + {tCommon('loading')} +
    + ) : ( + <> + {posts.length > 0 ? ( + + {posts.map(({ node }: { node: InterfacePostNode }) => { + const cardProps = getCardProps(node); + return ; + })} + + ) : ( +

    + {t(`nothingToShowHere`)} +

    + )} + + )} + +
    +
    + + ); +} diff --git a/src/screens/UserPortal/Settings/Settings.module.css b/src/screens/UserPortal/Settings/Settings.module.css new file mode 100644 index 0000000000..323aed3275 --- /dev/null +++ b/src/screens/UserPortal/Settings/Settings.module.css @@ -0,0 +1,179 @@ +.mainContainer { + flex-grow: 3; + max-height: 100%; + overflow: auto; +} + +.containerHeight { + padding: 1rem 1.5rem 0 calc(300px + 1.5rem); + height: 100vh; +} + +.expand { + padding-left: 4rem; + animation: moveLeft 0.9s ease-in-out; +} + +.contract { + padding-left: calc(300px + 2rem + 1.5rem); + animation: moveRight 0.5s ease-in-out; +} + +.cardHeader .cardTitle { + font-size: 1.2rem; + font-weight: 600; +} + +.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; +} + +.cardLabel { + font-weight: bold; + padding-bottom: 1px; + font-size: 14px; + color: #707070; + margin-bottom: 10px; +} + +.cardControl { + margin-bottom: 20px; +} + +.cardButton { + width: fit-content; +} + +.imgContianer { + margin: 0 2rem 0 0; +} + +.imgContianer img { + height: 120px; + width: 120px; + border-radius: 50%; +} + +.profileDetails { + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-evenly; +} + +.collapseSidebarButton { + position: fixed; + height: 40px; + bottom: 0; + z-index: 9999; + width: calc(300px + 2rem); + background-color: rgba(245, 245, 245, 0.7); + color: black; + border: none; + border-radius: 0px; +} + +.collapseSidebarButton:hover, +.opendrawer:hover { + opacity: 1; + color: black !important; +} +.opendrawer { + position: fixed; + display: flex; + align-items: center; + justify-content: center; + top: 0; + left: 0; + width: 40px; + height: 100vh; + z-index: 9999; + background-color: rgba(245, 245, 245); + border: none; + border-radius: 0px; + margin-right: 20px; + color: black; +} + +.opendrawer:hover { + transition: background-color 0.5s ease; + background-color: var(--bs-primary); +} +.collapseSidebarButton:hover { + transition: background-color 0.5s ease; + background-color: var(--bs-primary); +} + +@media (max-width: 1120px) { + .collapseSidebarButton { + width: calc(250px); + } +} + +@media (max-height: 650px) { + .collapseSidebarButton { + width: 250px; + height: 20px; + } + .opendrawer { + width: 30px; + } +} + +/* For tablets */ +@media (max-width: 820px) { + .containerHeight { + height: 100vh; + padding: 2rem; + } + + .contract, + .expand { + animation: none; + } + + .opendrawer { + width: 25px; + } + + .collapseSidebarButton { + width: 100%; + left: 0; + right: 0; + } +} + +@media screen and (max-width: 1280px) and (min-width: 992px) { + .imgContianer { + margin: 1rem auto; + } + .profileContainer { + flex-direction: column; + } +} + +@media screen and (max-width: 992px) { + .profileContainer { + align-items: center; + justify-content: center; + } +} + +@media screen and (max-width: 420px) { + .imgContianer { + margin: 1rem auto; + } + .profileContainer { + flex-direction: column; + } +} diff --git a/src/screens/UserPortal/Settings/Settings.test.tsx b/src/screens/UserPortal/Settings/Settings.test.tsx new file mode 100644 index 0000000000..eccf59aaab --- /dev/null +++ b/src/screens/UserPortal/Settings/Settings.test.tsx @@ -0,0 +1,509 @@ +import React from 'react'; +import { act, fireEvent, render, screen } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider } from 'react-i18next'; +import { UPDATE_USER_MUTATION } from 'GraphQl/Mutations/mutations'; +import { BrowserRouter } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import Settings from './Settings'; +import userEvent from '@testing-library/user-event'; +import { CHECK_AUTH } from 'GraphQl/Queries/Queries'; + +const MOCKS = [ + { + request: { + query: UPDATE_USER_MUTATION, + variables: { + firstName: 'Noble', + lastName: 'Mittal', + createdAt: '2021-03-01', + gender: 'MALE', + phoneNumber: '+174567890', + birthDate: '2024-03-01', + grade: 'GRADE_1', + empStatus: 'UNEMPLOYED', + maritalStatus: 'SINGLE', + address: 'random', + state: 'random', + country: 'IN', + }, + result: { + data: { + updateUserProfile: { + _id: '453', + }, + }, + }, + }, + }, +]; + +const Mocks1 = [ + { + request: { + query: CHECK_AUTH, + }, + result: { + data: { + checkAuth: { + email: 'johndoe@gmail.com', + firstName: 'John', + lastName: 'Doe', + createdAt: '2021-03-01T00:00:00.000Z', + gender: 'MALE', + maritalStatus: 'SINGLE', + educationGrade: 'GRADUATE', + employmentStatus: 'PART_TIME', + birthDate: '2024-03-01', + address: { + state: 'random', + countryCode: 'IN', + line1: 'random', + }, + phone: { + mobile: '+174567890', + }, + image: 'https://api.dicebear.com/5.x/initials/svg?seed=John%20Doe', + _id: '65ba1621b7b00c20e5f1d8d2', + }, + }, + }, + }, +]; + +const Mocks2 = [ + { + request: { + query: CHECK_AUTH, + }, + result: { + data: { + checkAuth: { + email: 'johndoe@gmail.com', + firstName: '', + lastName: '', + createdAt: '', + gender: '', + maritalStatus: '', + educationGrade: '', + employmentStatus: '', + birthDate: '', + address: { + state: '', + countryCode: '', + line1: '', + }, + phone: { + mobile: '', + }, + image: '', + _id: '65ba1621b7b00c20e5f1d8d2', + }, + }, + }, + }, +]; + +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); + +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 Settings Screen [User Portal]', () => { + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // Deprecated + removeListener: jest.fn(), // Deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), + }); + + test('Screen should be rendered properly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + expect(screen.queryAllByText('Settings')).not.toBe([]); + }); + + test('input works properly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.type(screen.getByTestId('inputFirstName'), 'Noble'); + await wait(); + userEvent.type(screen.getByTestId('inputLastName'), 'Mittal'); + await wait(); + userEvent.selectOptions(screen.getByTestId('inputGender'), 'Male'); + await wait(); + userEvent.type(screen.getByTestId('inputPhoneNumber'), '1234567890'); + await wait(); + userEvent.selectOptions(screen.getByTestId('inputGrade'), 'Grade 1'); + await wait(); + userEvent.selectOptions(screen.getByTestId('inputEmpStatus'), 'Unemployed'); + await wait(); + userEvent.selectOptions(screen.getByTestId('inputMaritalStatus'), 'Single'); + await wait(); + userEvent.type(screen.getByTestId('inputAddress'), 'random'); + await wait(); + userEvent.type(screen.getByTestId('inputState'), 'random'); + await wait(); + userEvent.selectOptions(screen.getByTestId('inputCountry'), 'IN'); + await wait(); + expect(screen.getByTestId('resetChangesBtn')).toBeInTheDocument(); + await wait(); + fireEvent.change(screen.getByLabelText('Birth Date'), { + target: { value: '2024-03-01' }, + }); + expect(screen.getByLabelText('Birth Date')).toHaveValue('2024-03-01'); + await wait(); + const fileInp = screen.getByTestId('fileInput'); + fileInp.style.display = 'block'; + userEvent.click(screen.getByTestId('uploadImageBtn')); + await wait(); + const imageFile = new File(['(⌐□_□)'], 'profile-image.jpg', { + type: 'image/jpeg', + }); + const files = [imageFile]; + userEvent.upload(fileInp, files); + await wait(); + expect(screen.getAllByAltText('profile picture')[0]).toBeInTheDocument(); + }); + + test('resetChangesBtn works properly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('resetChangesBtn')); + await wait(); + expect(screen.getByTestId('inputFirstName')).toHaveValue('John'); + expect(screen.getByTestId('inputLastName')).toHaveValue('Doe'); + expect(screen.getByTestId('inputGender')).toHaveValue('MALE'); + expect(screen.getByTestId('inputPhoneNumber')).toHaveValue('+174567890'); + expect(screen.getByTestId('inputGrade')).toHaveValue('GRADUATE'); + expect(screen.getByTestId('inputEmpStatus')).toHaveValue('PART_TIME'); + expect(screen.getByTestId('inputMaritalStatus')).toHaveValue('SINGLE'); + expect(screen.getByTestId('inputAddress')).toHaveValue('random'); + expect(screen.getByTestId('inputState')).toHaveValue('random'); + expect(screen.getByTestId('inputCountry')).toHaveValue('IN'); + expect(screen.getByLabelText('Birth Date')).toHaveValue('2024-03-01'); + }); + + test('resetChangesBtn works properly when the details are empty', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('resetChangesBtn')); + await wait(); + expect(screen.getByTestId('inputFirstName')).toHaveValue(''); + expect(screen.getByTestId('inputLastName')).toHaveValue(''); + expect(screen.getByTestId('inputGender')).toHaveValue(''); + expect(screen.getByTestId('inputPhoneNumber')).toHaveValue(''); + expect(screen.getByTestId('inputGrade')).toHaveValue(''); + expect(screen.getByTestId('inputEmpStatus')).toHaveValue(''); + expect(screen.getByTestId('inputMaritalStatus')).toHaveValue(''); + expect(screen.getByTestId('inputAddress')).toHaveValue(''); + expect(screen.getByTestId('inputState')).toHaveValue(''); + expect(screen.getByTestId('inputCountry')).toHaveValue(''); + expect(screen.getByLabelText('Birth Date')).toHaveValue(''); + }); + + test('sidebar', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + const closeMenubtn = screen.getByTestId('closeMenu'); + expect(closeMenubtn).toBeInTheDocument(); + closeMenubtn.click(); + const openMenuBtn = screen.getByTestId('openMenu'); + expect(openMenuBtn).toBeInTheDocument(); + openMenuBtn.click(); + }); + + test('Testing sidebar when the screen size is less than or equal to 820px', async () => { + resizeWindow(800); + render( + + + + + + + + + , + ); + await wait(); + expect(screen.getByText('My Organizations')).toBeInTheDocument(); + expect(screen.getByText('Talawa User Portal')).toBeInTheDocument(); + + const settingsBtn = screen.getByTestId('settingsBtn'); + + settingsBtn.click(); + }); + + test('updateUserDetails Mutation is triggered on button click', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.type(screen.getByTestId('inputFirstName'), 'Noble'); + await wait(); + + userEvent.type(screen.getByTestId('inputLastName'), 'Mittal'); + await wait(); + + userEvent.selectOptions(screen.getByTestId('inputGender'), 'OTHER'); + await wait(); + + userEvent.type(screen.getByTestId('inputPhoneNumber'), '+174567890'); + await wait(); + + fireEvent.change(screen.getByLabelText('Birth Date'), { + target: { value: '2024-03-01' }, + }); + await wait(); + + userEvent.selectOptions(screen.getByTestId('inputGrade'), 'Graduate'); + await wait(); + + userEvent.selectOptions(screen.getByTestId('inputEmpStatus'), 'Unemployed'); + await wait(); + + userEvent.selectOptions(screen.getByTestId('inputMaritalStatus'), 'Single'); + await wait(); + + userEvent.type(screen.getByTestId('inputAddress'), 'random'); + await wait(); + + userEvent.type(screen.getByTestId('inputState'), 'random'); + await wait(); + + userEvent.click(screen.getByTestId('updateUserBtn')); + await wait(); + }); + + test('Marital Status dropdown value verification', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + // SINGLE + expect( + screen.queryByRole('option', { name: mockMaritalStatusEnum[0].label }), + ).toBeInTheDocument(); + + userEvent.selectOptions( + // Find the select element + screen.getByTestId('inputMaritalStatus'), + // Find and select the Single option + screen.getByRole('option', { name: mockMaritalStatusEnum[0].label }), + ); + + expect(screen.getByTestId('inputMaritalStatus')).toHaveValue( + mockMaritalStatusEnum[0].value, + ); + + // ENGAGED + expect( + screen.queryByRole('option', { name: mockMaritalStatusEnum[1].label }), + ).toBeInTheDocument(); + + userEvent.selectOptions( + // Find the select element + screen.getByTestId('inputMaritalStatus'), + // Find and select the Engaged option + screen.getByRole('option', { name: mockMaritalStatusEnum[1].label }), + ); + + expect(screen.getByTestId('inputMaritalStatus')).toHaveValue( + mockMaritalStatusEnum[1].value, + ); + + // MARRIED + expect( + screen.queryByRole('option', { name: mockMaritalStatusEnum[2].label }), + ).toBeInTheDocument(); + + userEvent.selectOptions( + // Find the select element + screen.getByTestId('inputMaritalStatus'), + // Find and select the Married option + screen.getByRole('option', { name: mockMaritalStatusEnum[2].label }), + ); + + expect(screen.getByTestId('inputMaritalStatus')).toHaveValue( + mockMaritalStatusEnum[2].value, + ); + + // DIVORCED + expect( + screen.queryByRole('option', { name: mockMaritalStatusEnum[3].label }), + ).toBeInTheDocument(); + + userEvent.selectOptions( + // Find the select element + screen.getByTestId('inputMaritalStatus'), + // Find and select the Divorced option + screen.getByRole('option', { name: mockMaritalStatusEnum[3].label }), + ); + + expect(screen.getByTestId('inputMaritalStatus')).toHaveValue( + mockMaritalStatusEnum[3].value, + ); + + // WIDOWED + expect( + screen.queryByRole('option', { name: mockMaritalStatusEnum[4].label }), + ).toBeInTheDocument(); + + userEvent.selectOptions( + // Find the select element + screen.getByTestId('inputMaritalStatus'), + // Find and select the Widowed option + screen.getByRole('option', { name: mockMaritalStatusEnum[4].label }), + ); + + expect(screen.getByTestId('inputMaritalStatus')).toHaveValue( + mockMaritalStatusEnum[4].value, + ); + + // SEPARATED + expect( + screen.queryByRole('option', { name: mockMaritalStatusEnum[5].label }), + ).toBeInTheDocument(); + + userEvent.selectOptions( + // Find the select element + screen.getByTestId('inputMaritalStatus'), + // Find and select the Separated option + screen.getByRole('option', { name: mockMaritalStatusEnum[5].label }), + ); + + expect(screen.getByTestId('inputMaritalStatus')).toHaveValue( + mockMaritalStatusEnum[5].value, + ); + }, 60000); +}); diff --git a/src/screens/UserPortal/Settings/Settings.tsx b/src/screens/UserPortal/Settings/Settings.tsx new file mode 100644 index 0000000000..9fb63cd8e1 --- /dev/null +++ b/src/screens/UserPortal/Settings/Settings.tsx @@ -0,0 +1,605 @@ +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'; +import convertToBase64 from 'utils/convertToBase64'; +import { UPDATE_USER_MUTATION } from 'GraphQl/Mutations/mutations'; +import { useMutation, useQuery } from '@apollo/client'; +import { errorHandler } from 'utils/errorHandler'; +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 { create } from 'domain'; + +export default function settings(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'settings', + }); + const { t: tCommon } = useTranslation('common'); + + const [hideDrawer, setHideDrawer] = useState(null); + + const handleResize = (): void => { + if (window.innerWidth <= 820) { + setHideDrawer(!hideDrawer); + } + }; + + useEffect(() => { + handleResize(); + window.addEventListener('resize', handleResize); + return () => { + window.removeEventListener('resize', handleResize); + }; + }, []); + + const { setItem } = useLocalStorage(); + + const { data } = useQuery(CHECK_AUTH, { fetchPolicy: 'network-only' }); + const [updateUserDetails] = useMutation(UPDATE_USER_MUTATION); + + const [userDetails, setUserDetails] = React.useState({ + firstName: '', + lastName: '', + createdAt: '', + gender: '', + email: '', + phoneNumber: '', + birthDate: '', + grade: '', + empStatus: '', + maritalStatus: '', + address: '', + state: '', + country: '', + image: '', + }); + + const originalImageState = React.useRef(''); + const fileInputRef = React.useRef(null); + const handleUpdateUserDetails = async (): Promise => { + try { + let updatedUserDetails = { ...userDetails }; + if (updatedUserDetails.image === originalImageState.current) { + updatedUserDetails = { ...updatedUserDetails, image: '' }; + } + const { data } = await updateUserDetails({ + variables: updatedUserDetails, + }); + /* istanbul ignore next */ + if (data) { + toast.success(tCommon('updatedSuccessfully', { item: 'Profile' })); + setTimeout(() => { + window.location.reload(); + }, 500); + + const userFullName = `${userDetails.firstName} ${userDetails.lastName}`; + setItem('name', userFullName); + } + } catch (error: unknown) { + errorHandler(t, error); + } + }; + + const handleFieldChange = (fieldName: string, value: string): void => { + setUserDetails((prevState) => ({ + ...prevState, + [fieldName]: value, + })); + }; + + const handleImageUpload = (): void => { + if (fileInputRef.current) { + (fileInputRef.current as HTMLInputElement).click(); + } + }; + + const handleResetChanges = (): void => { + /* istanbul ignore next */ + if (data) { + const { + firstName, + lastName, + createdAt, + gender, + phone, + birthDate, + educationGrade, + employmentStatus, + maritalStatus, + address, + } = data.checkAuth; + + setUserDetails({ + ...userDetails, + firstName: firstName || '', + lastName: lastName || '', + createdAt: createdAt || '', + gender: gender || '', + phoneNumber: phone?.mobile || '', + birthDate: birthDate || '', + grade: educationGrade || '', + empStatus: employmentStatus || '', + maritalStatus: maritalStatus || '', + address: address?.line1 || '', + state: address?.state || '', + country: address?.countryCode || '', + }); + } + }; + + React.useEffect(() => { + /* istanbul ignore next */ + if (data) { + const { + firstName, + lastName, + createdAt, + gender, + email, + phone, + birthDate, + educationGrade, + employmentStatus, + maritalStatus, + address, + image, + } = data.checkAuth; + + setUserDetails({ + firstName, + lastName, + createdAt, + gender, + email, + phoneNumber: phone?.mobile || '', + birthDate, + grade: educationGrade || '', + empStatus: employmentStatus || '', + maritalStatus: maritalStatus || '', + address: address?.line1 || '', + state: address?.state || '', + country: address?.countryCode || '', + image, + }); + originalImageState.current = image; + } + }, [data]); + + return ( + <> + {hideDrawer ? ( + + ) : ( + + )} + +
    +
    +
    + +
    +

    {tCommon('settings')}

    + + + + + + +
    +
    + {t('profileSettings')} +
    +
    + + + + + {tCommon('firstName')} + + + handleFieldChange('firstName', e.target.value) + } + className={`${styles.cardControl}`} + data-testid="inputFirstName" + /> + + + + {tCommon('lastName')} + + + handleFieldChange('lastName', e.target.value) + } + className={`${styles.cardControl}`} + data-testid="inputLastName" + /> + + + + {t('gender')} + + + handleFieldChange('gender', e.target.value) + } + className={`${styles.cardControl}`} + data-testid="inputGender" + > + + {genderEnum.map((g) => ( + + ))} + + + + + + + {tCommon('emailAddress')} + + + + + + {t('phoneNumber')} + + + handleFieldChange('phoneNumber', e.target.value) + } + className={`${styles.cardControl}`} + 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('birthDate')} + + + handleFieldChange('birthDate', e.target.value) + } + className={`${styles.cardControl}`} + /> + + + + {t('grade')} + + + handleFieldChange('grade', e.target.value) + } + className={`${styles.cardControl}`} + data-testid="inputGrade" + > + + {educationGradeEnum.map((grade) => ( + + ))} + + + + + + + {t('empStatus')} + + + handleFieldChange('empStatus', e.target.value) + } + className={`${styles.cardControl}`} + data-testid="inputEmpStatus" + > + + {employmentStatusEnum.map((status) => ( + + ))} + + + + + {t('maritalStatus')} + + + handleFieldChange('maritalStatus', e.target.value) + } + className={`${styles.cardControl}`} + data-testid="inputMaritalStatus" + > + + {maritalStatusEnum.map((status) => ( + + ))} + + + + + + + {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.map((country) => ( + + ))} + + + +
    + + +
    +
    +
    + + + + + + + + + + +
    +
    +
    + + ); +} diff --git a/src/screens/UserPortal/UserScreen/UserScreen.module.css b/src/screens/UserPortal/UserScreen/UserScreen.module.css new file mode 100644 index 0000000000..f8ad1c5bfd --- /dev/null +++ b/src/screens/UserPortal/UserScreen/UserScreen.module.css @@ -0,0 +1,173 @@ +.pageContainer { + display: flex; + flex-direction: column; + min-height: 100vh; + padding: 1rem 1.5rem 0 calc(300px + 2rem + 1.5rem); +} + +.expand { + padding-left: 4rem; + animation: moveLeft 0.9s ease-in-out; +} +.avatarStyle { + border-radius: 100%; +} +.profileContainer { + border: none; + padding: 2.1rem 0.5rem; + height: 52px; + border-radius: 8px 0px 0px 8px; + display: flex; + align-items: center; + background-color: white !important; + box-shadow: + 0 4px 4px 0 rgba(177, 177, 177, 0.2), + 0 6px 20px 0 rgba(151, 151, 151, 0.19); +} +.profileContainer:focus { + outline: none; + background-color: var(--bs-gray-100); +} +.imageContainer { + width: 56px; +} +.profileContainer .profileText { + flex: 1; + text-align: start; + overflow: hidden; + margin-right: 4px; +} +.angleDown { + margin-left: 4px; +} +.profileContainer .profileText .primaryText { + font-size: 1rem; + font-weight: 600; + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 2; /* number of lines to show */ + -webkit-box-orient: vertical; + word-wrap: break-word; + white-space: normal; +} +.profileContainer .profileText .secondaryText { + font-size: 0.8rem; + font-weight: 400; + color: var(--bs-secondary); + display: block; + text-transform: capitalize; +} + +.contract { + padding-left: calc(300px + 2rem + 1.5rem); + animation: moveRight 0.5s ease-in-out; +} + +.collapseSidebarButton { + position: fixed; + height: 40px; + bottom: 0; + z-index: 9999; + width: calc(300px + 2rem); + background-color: rgba(245, 245, 245, 0.7); + color: black; + border: none; + border-radius: 0px; +} + +.collapseSidebarButton:hover, +.opendrawer:hover { + opacity: 1; + color: black !important; +} +.opendrawer { + position: fixed; + display: flex; + align-items: center; + justify-content: center; + top: 0; + left: 0; + width: 40px; + height: 100vh; + z-index: 9999; + background-color: rgba(245, 245, 245); + border: none; + border-radius: 0px; + margin-right: 20px; + color: black; +} +.profileDropdown { + background-color: transparent !important; +} +.profileDropdown .dropdown-toggle .btn .btn-normal { + display: none !important; + background-color: transparent !important; +} +.dropdownToggle { + background-image: url(/public/images/svg/angleDown.svg); + background-repeat: no-repeat; + background-position: center; + background-color: azure; +} + +.dropdownToggle::after { + border-top: none !important; + border-bottom: none !important; +} + +.opendrawer:hover { + transition: background-color 0.5s ease; + background-color: var(--bs-primary); +} +.collapseSidebarButton:hover { + transition: background-color 0.5s ease; + background-color: var(--bs-primary); +} + +@media (max-width: 1120px) { + .contract { + padding-left: calc(276px + 2rem + 1.5rem); + } + .collapseSidebarButton { + width: calc(250px + 2rem); + } +} + +@media (max-height: 900px) { + .collapseSidebarButton { + width: calc(300px + 1rem); + } +} +@media (max-height: 650px) { + .pageContainer { + padding: 1rem 1.5rem 0 calc(270px); + } + .collapseSidebarButton { + width: 250px; + } + .opendrawer { + width: 30px; + } +} + +/* For tablets */ +@media (max-width: 820px) { + .pageContainer { + padding-left: 2.5rem; + } + + .opendrawer { + width: 25px; + } + + .contract, + .expand { + animation: none; + } + + .collapseSidebarButton { + width: 100%; + left: 0; + right: 0; + } +} diff --git a/src/screens/UserPortal/UserScreen/UserScreen.test.tsx b/src/screens/UserPortal/UserScreen/UserScreen.test.tsx new file mode 100644 index 0000000000..3600e7a991 --- /dev/null +++ b/src/screens/UserPortal/UserScreen/UserScreen.test.tsx @@ -0,0 +1,117 @@ +import React from 'react'; +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 { 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'; + +let mockID: string | undefined = '123'; +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: mockID }), +})); + +const MOCKS = [ + { + request: { + query: ORGANIZATIONS_LIST, + variables: { id: '123' }, + }, + result: { + data: { + organizations: [ + { + _id: '123', + image: null, + creator: { + firstName: 'John', + lastName: 'Doe', + email: 'JohnDoe@example.com', + }, + name: 'Test Organization', + description: 'Testing this organization', + address: { + city: 'Mountain View', + countryCode: 'US', + dependentLocality: 'Some Dependent Locality', + line1: '123 Main Street', + line2: 'Apt 456', + postalCode: '94040', + sortingCode: 'XYZ-789', + state: 'CA', + }, + userRegistrationRequired: true, + visibleInSearch: true, + members: [], + admins: [], + membershipRequests: [], + blockedUsers: [], + }, + ], + }, + }, + }, +]; +const link = new StaticMockLink(MOCKS, true); + +const resizeWindow = (width: number): void => { + window.innerWidth = width; + fireEvent(window, new Event('resize')); +}; + +const clickToggleMenuBtn = (toggleButton: HTMLElement): void => { + fireEvent.click(toggleButton); +}; + +describe('Testing LeftDrawer in OrganizationScreen', () => { + test('Testing LeftDrawer in page functionality', async () => { + render( + + + + + + + + + , + ); + const toggleButton = screen.getByTestId('closeMenu') as HTMLElement; + const icon = toggleButton.querySelector('i'); + + // Resize window to a smaller width + resizeWindow(800); + clickToggleMenuBtn(toggleButton); + expect(icon).toHaveClass('fa fa-angle-double-left'); + // Resize window back to a larger width + + resizeWindow(1000); + clickToggleMenuBtn(toggleButton); + expect(icon).toHaveClass('fa fa-angle-double-right'); + + clickToggleMenuBtn(toggleButton); + expect(icon).toHaveClass('fa fa-angle-double-left'); + }); + + test('should be redirected to / if orgId is undefined', async () => { + mockID = undefined; + render( + + + + + + + + + , + ); + expect(window.location.pathname).toEqual('/'); + }); +}); diff --git a/src/screens/UserPortal/UserScreen/UserScreen.tsx b/src/screens/UserPortal/UserScreen/UserScreen.tsx new file mode 100644 index 0000000000..a1605fa59d --- /dev/null +++ b/src/screens/UserPortal/UserScreen/UserScreen.tsx @@ -0,0 +1,97 @@ +import React, { useEffect, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { Navigate, Outlet, useLocation, useParams } from 'react-router-dom'; +import { updateTargets } from 'state/action-creators'; +import type { RootState } from 'state/reducers'; +import type { TargetsType } from 'state/reducers/routesReducer'; +import styles from './UserScreen.module.css'; +import { Button } from 'react-bootstrap'; +import UserSidebarOrg from 'components/UserPortal/UserSidebarOrg/UserSidebarOrg'; +import ProfileDropdown from 'components/ProfileDropdown/ProfileDropdown'; + +const UserScreen = (): JSX.Element => { + const location = useLocation(); + const [hideDrawer, setHideDrawer] = useState(null); + const { orgId } = useParams(); + + if (!orgId) { + return ; + } + + const appRoutes: { + targets: TargetsType[]; + } = useSelector((state: RootState) => state.userRoutes); + const { targets } = appRoutes; + + console.log(location.pathname.split('/')); + + const dispatch = useDispatch(); + useEffect(() => { + dispatch(updateTargets(orgId)); + }, [orgId]); // Added orgId to the dependency array + + const handleResize = (): void => { + if (window.innerWidth <= 820) { + setHideDrawer(!hideDrawer); + } + }; + + useEffect(() => { + handleResize(); + window.addEventListener('resize', handleResize); + return () => { + window.removeEventListener('resize', handleResize); + }; + }, []); + + return ( + <> + {hideDrawer ? ( + + ) : ( + + )} +
    + +
    +
    +
    + +
    + +
    + + ); +}; + +export default UserScreen; diff --git a/src/screens/Users/Users.module.css b/src/screens/Users/Users.module.css new file mode 100644 index 0000000000..0750dba108 --- /dev/null +++ b/src/screens/Users/Users.module.css @@ -0,0 +1,95 @@ +.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.test.tsx b/src/screens/Users/Users.test.tsx new file mode 100644 index 0000000000..f130ed1df9 --- /dev/null +++ b/src/screens/Users/Users.test.tsx @@ -0,0 +1,714 @@ +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); + + // 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'); + + fireEvent.click(inputText); + const toggleText = screen.getByTestId('admin'); + fireEvent.click(toggleText); + + expect(searchInput).toBeInTheDocument(); + + fireEvent.click(inputText); + let toggleTite = screen.getByTestId('superAdmin'); + fireEvent.click(toggleTite); + + expect(searchInput).toBeInTheDocument(); + + fireEvent.click(inputText); + toggleTite = screen.getByTestId('user'); + fireEvent.click(toggleTite); + + expect(searchInput).toBeInTheDocument(); + + fireEvent.click(inputText); + toggleTite = screen.getByTestId('cancel'); + 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'); + fireEvent.click(filterButton); + + const filterAdmin = screen.getByTestId('admin'); + fireEvent.click(filterAdmin); + await wait(); + expect(screen.getByText('Jane Doe')).toBeInTheDocument(); + + fireEvent.click(filterButton); + const filterSuperAdmin = screen.getByTestId('superAdmin'); + fireEvent.click(filterSuperAdmin); + await wait(); + expect(screen.getByText('John Doe')).toBeInTheDocument(); + + fireEvent.click(filterButton); + const filterUser = screen.getByTestId('user'); + fireEvent.click(filterUser); + await wait(); + expect(screen.getByText('Jack Smith')).toBeInTheDocument(); + + fireEvent.click(filterButton); + const filterCancel = screen.getByTestId('cancel'); + 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'); + + fireEvent.click(inputText); + const toggleText = screen.getByTestId('oldest'); + fireEvent.click(toggleText); + + fireEvent.click(inputText); + const toggleTite = screen.getByTestId('newest'); + 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(); + + fireEvent.click(inputText); + const toggleOld = screen.getByTestId('oldest'); + fireEvent.click(toggleOld); + + fireEvent.click(inputText); + const toggleNewest = screen.getByTestId('newest'); + fireEvent.click(toggleNewest); + }); + }); +}); diff --git a/src/screens/Users/Users.tsx b/src/screens/Users/Users.tsx new file mode 100644 index 0000000000..3dae6ec17e --- /dev/null +++ b/src/screens/Users/Users.tsx @@ -0,0 +1,439 @@ +import { useQuery } from '@apollo/client'; +import React, { useEffect, useState } from 'react'; +import { Dropdown, Form, Table } from 'react-bootstrap'; +import Button from 'react-bootstrap/Button'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; + +import { Search } from '@mui/icons-material'; +import FilterListIcon from '@mui/icons-material/FilterList'; +import SortIcon from '@mui/icons-material/Sort'; +import { + ORGANIZATION_CONNECTION_LIST, + USER_LIST, +} from 'GraphQl/Queries/Queries'; +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 useLocalStorage from 'utils/useLocalstorage'; +import type { ApolloError } from '@apollo/client'; + +const Users = (): JSX.Element => { + const { t } = useTranslation('translation', { keyPrefix: 'users' }); + const { t: tCommon } = useTranslation('common'); + + document.title = t('title'); + + const { getItem } = useLocalStorage(); + + const perPageResult = 12; + 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 userType = getItem('SuperAdmin') + ? 'SUPERADMIN' + : getItem('AdminFor') + ? 'ADMIN' + : 'USER'; + const loggedInUserId = getItem('id'); + + const { + data: usersData, + loading: loading, + fetchMore, + refetch: refetchUsers, + }: { + data?: { users: InterfaceQueryUserListItem[] }; + loading: boolean; + fetchMore: any; + refetch: any; + error?: ApolloError; + } = useQuery(USER_LIST, { + variables: { + first: perPageResult, + skip: 0, + firstName_contains: '', + lastName_contains: '', + order: sortingOption === 'newest' ? 'createdAt_DESC' : 'createdAt_ASC', + }, + notifyOnNetworkStatusChange: true, + }); + + const { data: dataOrgs } = useQuery(ORGANIZATION_CONNECTION_LIST); + const [displayedUsers, setDisplayedUsers] = useState(usersData?.users || []); + + // Manage loading more state + useEffect(() => { + 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); + } + }, [usersData, sortingOption, filteringOption]); + + // To clear the search when the component is unmounted + useEffect(() => { + return () => { + setSearchByName(''); + }; + }, []); + + // Warn if there is no organization + useEffect(() => { + if (!dataOrgs) { + return; + } + + if (dataOrgs.organizationsConnection.length === 0) { + toast.warning(t('noOrgError')); + } + }, [dataOrgs]); + + // Send to orgList page if user is not superadmin + useEffect(() => { + if (userType != 'SUPERADMIN') { + window.location.assign('/orglist'); + } + }, []); + + // Manage the loading state + useEffect(() => { + if (loading && isLoadingMore == false) { + setIsLoading(true); + } else { + setIsLoading(false); + } + }, [loading]); + + const handleSearch = (value: string): void => { + setSearchByName(value); + if (value === '') { + resetAndRefetch(); + return; + } + refetchUsers({ + firstName_contains: value, + lastName_contains: '', + // Later on we can add several search and filter options + }); + setHasMore(true); + }; + + const handleSearchByEnter = (e: any): void => { + if (e.key === 'Enter') { + const { value } = e.target; + handleSearch(value); + } + }; + + const handleSearchByBtnClick = (): void => { + const inputElement = document.getElementById( + 'searchUsers', + ) as HTMLInputElement; + const inputValue = inputElement?.value || ''; + handleSearch(inputValue); + }; + /* istanbul ignore next */ + const resetAndRefetch = (): void => { + refetchUsers({ + first: perPageResult, + skip: 0, + firstName_contains: '', + lastName_contains: '', + order: sortingOption === 'newest' ? 'createdAt_DESC' : 'createdAt_ASC', + }); + setHasMore(true); + }; + /* istanbul ignore next */ + const loadMoreUsers = (): void => { + setIsLoadingMore(true); + fetchMore({ + variables: { + skip: usersData?.users.length || 0, + userType: 'ADMIN', + filter: searchByName, + order: sortingOption === 'newest' ? 'createdAt_DESC' : 'createdAt_ASC', + }, + updateQuery: ( + prev: { users: InterfaceQueryUserListItem[] } | undefined, + { + fetchMoreResult, + }: { + fetchMoreResult: { users: InterfaceQueryUserListItem[] } | undefined; + }, + ): { users: InterfaceQueryUserListItem[] } | undefined => { + setIsLoadingMore(false); + if (!fetchMoreResult) return prev; + if (fetchMoreResult.users.length < perPageResult) { + setHasMore(false); + } + return { + users: [...(prev?.users || []), ...(fetchMoreResult.users || [])], + }; + }, + }); + }; + + const handleSorting = (option: string): void => { + setDisplayedUsers([]); + setHasMore(true); + setSortingOption(option); + }; + + const sortUsers = ( + allUsers: InterfaceQueryUserListItem[], + sortingOption: string, + ): InterfaceQueryUserListItem[] => { + const sortedUsers = [...allUsers]; + + if (sortingOption === 'newest') { + sortedUsers.sort( + (a, b) => + new Date(b.user.createdAt).getTime() - + 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; + } + }; + + const handleFiltering = (option: string): void => { + setDisplayedUsers([]); + setFilteringOption(option); + }; + + const filterUsers = ( + allUsers: InterfaceQueryUserListItem[], + filteringOption: string, + ): InterfaceQueryUserListItem[] => { + const filteredUsers = [...allUsers]; + + if (filteringOption === 'cancel') { + return filteredUsers; + } else if (filteringOption === 'user') { + const output = filteredUsers.filter((user) => { + return user.appUserProfile.adminFor.length === 0; + }); + return output; + } else if (filteringOption === 'admin') { + const output = filteredUsers.filter((user) => { + return ( + user.appUserProfile.isSuperAdmin === false && + user.appUserProfile.adminFor.length !== 0 + ); + }); + return output; + } else { + const output = filteredUsers.filter((user) => { + return user.appUserProfile.isSuperAdmin === true; + }); + return output; + } + }; + + const headerTitles: string[] = [ + '#', + tCommon('name'), + tCommon('email'), + t('joined_organizations'), + t('blocked_organizations'), + ]; + + return ( + <> + {/* Buttons Container */} +
    +
    +
    + + +
    +
    +
    +
    + + +
    +
    +
    + {isLoading == false && + 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) => { + return ( + + ); + })} + + + + {usersData && + displayedUsers.map( + (user: InterfaceQueryUserListItem, index: number) => { + return ( + + ); + }, + )} + +
    + {title} +
    +
    + )} +
    + )} + + ); +}; + +export default Users; diff --git a/src/screens/Users/UsersMocks.ts b/src/screens/Users/UsersMocks.ts new file mode 100644 index 0000000000..ff346a1c97 --- /dev/null +++ b/src/screens/Users/UsersMocks.ts @@ -0,0 +1,505 @@ +import { + ORGANIZATION_CONNECTION_LIST, + USER_LIST, + USER_ORGANIZATION_LIST, +} from 'GraphQl/Queries/Queries'; + +export const MOCKS = [ + { + request: { + query: USER_ORGANIZATION_LIST, + variables: { id: 'user1' }, + }, + result: { + data: { + user: { + firstName: 'John', + lastName: 'Doe', + image: '', + email: 'John_Does_Palasidoes@gmail.com', + }, + }, + }, + }, + { + request: { + query: USER_LIST, + variables: { + first: 12, + skip: 0, + firstName_contains: '', + lastName_contains: '', + }, + }, + result: { + data: { + 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: '20/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: '20/06/2022', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '20/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: '20/06/2022', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '20/06/2022', + }, + }, + ], + }, + appUserProfile: { + _id: 'user2', + adminFor: [ + { + _id: '123', + }, + ], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, + ], + }, + }, + }, + { + request: { + query: ORGANIZATION_CONNECTION_LIST, + }, + result: { + data: { + organizationsConnection: [ + { + _id: 123, + image: null, + creator: { + firstName: 'John', + lastName: 'Doe', + }, + name: 'Palisadoes', + members: [ + { + _id: 'user1', + }, + { + _id: 'user2', + }, + ], + admins: [ + { + _id: 'user1', + }, + { + _id: 'user2', + }, + ], + createdAt: '09/11/2001', + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + }, + ], + }, + }, + }, +]; + +export const MOCKS2 = [ + { + request: { + query: USER_ORGANIZATION_LIST, + variables: { id: 'user1' }, + }, + result: { + data: { + user: { + firstName: 'John', + lastName: 'Doe', + image: '', + email: 'John_Does_Palasidoes@gmail.com', + }, + }, + }, + }, + { + request: { + query: USER_LIST, + variables: { + first: 12, + skip: 0, + firstName_contains: '', + lastName_contains: '', + }, + }, + result: { + data: { + 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: '20/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: '20/06/2022', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '20/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: '20/06/2022', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '20/06/2022', + }, + }, + ], + }, + appUserProfile: { + _id: 'user2', + adminFor: [ + { + _id: '123', + }, + ], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, + ], + }, + }, + }, + { + request: { + query: ORGANIZATION_CONNECTION_LIST, + }, + result: { + data: { + organizationsConnection: [ + { + _id: 123, + image: null, + creator: { + firstName: 'John', + lastName: 'Doe', + }, + name: 'Palisadoes', + members: [ + { + _id: 'user1', + }, + { + _id: 'user2', + }, + ], + admins: [ + { + _id: 'user1', + }, + { + _id: 'user2', + }, + ], + createdAt: '09/11/2001', + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + }, + ], + }, + }, + }, +]; + +export const EMPTY_MOCKS = [ + { + request: { + query: USER_LIST, + + variables: { + first: 12, + skip: 0, + firstName_contains: '', + lastName_contains: '', + }, + }, + result: { + data: { + users: [], + }, + }, + }, + { + request: { + query: ORGANIZATION_CONNECTION_LIST, + }, + result: { + data: { + organizationsConnection: [], + }, + }, + }, +]; diff --git a/src/setup/askForCustomPort/askForCustomPort.test.ts b/src/setup/askForCustomPort/askForCustomPort.test.ts new file mode 100644 index 0000000000..0df6259ba1 --- /dev/null +++ b/src/setup/askForCustomPort/askForCustomPort.test.ts @@ -0,0 +1,24 @@ +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 new file mode 100644 index 0000000000..8a923f678f --- /dev/null +++ b/src/setup/askForCustomPort/askForCustomPort.ts @@ -0,0 +1,14 @@ +import inquirer from 'inquirer'; + +export async function askForCustomPort(): Promise { + const { customPort } = await inquirer.prompt([ + { + type: 'input', + name: 'customPort', + message: + 'Enter custom port for development server (leave blank for default 4321):', + default: 4321, + }, + ]); + return customPort; +} diff --git a/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.test.ts b/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.test.ts new file mode 100644 index 0000000000..b1490222b4 --- /dev/null +++ b/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.test.ts @@ -0,0 +1,58 @@ +import inquirer from 'inquirer'; +import { askForTalawaApiUrl } from './askForTalawaApiUrl'; + +jest.mock('inquirer', () => ({ + prompt: jest.fn(), +})); + +describe('askForTalawaApiUrl', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + test('should return the provided endpoint when user enters it', async () => { + const mockPrompt = jest.spyOn(inquirer, 'prompt').mockResolvedValueOnce({ + endpoint: 'http://example.com/graphql/', + }); + + const result = await askForTalawaApiUrl(); + + expect(mockPrompt).toHaveBeenCalledWith([ + { + type: 'input', + name: 'endpoint', + message: 'Enter your talawa-api endpoint:', + default: 'http://localhost:4000/graphql/', + }, + ]); + + expect(result).toBe('http://example.com/graphql/'); + }); + + 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 result = await askForTalawaApiUrl(); + + expect(mockPrompt).toHaveBeenCalledWith([ + { + type: 'input', + name: 'endpoint', + message: 'Enter your talawa-api endpoint:', + default: 'http://localhost:4000/graphql/', + }, + ]); + + expect(result).toBe('http://localhost:4000/graphql/'); + }); +}); diff --git a/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.ts b/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.ts new file mode 100644 index 0000000000..97daa1ac89 --- /dev/null +++ b/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.ts @@ -0,0 +1,13 @@ +import inquirer from 'inquirer'; + +export async function askForTalawaApiUrl(): Promise { + const { endpoint } = await inquirer.prompt([ + { + type: 'input', + name: 'endpoint', + message: 'Enter your talawa-api endpoint:', + default: 'http://localhost:4000/graphql/', + }, + ]); + return endpoint; +} diff --git a/src/setup/checkConnection/checkConnection.test.ts b/src/setup/checkConnection/checkConnection.test.ts new file mode 100644 index 0000000000..c6f5251bdf --- /dev/null +++ b/src/setup/checkConnection/checkConnection.test.ts @@ -0,0 +1,55 @@ +import { checkConnection } from './checkConnection'; + +jest.mock('node-fetch'); + +global.fetch = jest.fn((url) => { + if (url === 'http://example.com/graphql/') { + const responseInit: ResponseInit = { + status: 200, + statusText: 'OK', + headers: new Headers({ 'Content-Type': 'application/json' }), + }; + return Promise.resolve(new Response(JSON.stringify({}), responseInit)); + } else { + const errorResponseInit: ResponseInit = { + status: 500, + statusText: 'Internal Server Error', + headers: new Headers({ 'Content-Type': 'text/plain' }), + }; + return Promise.reject(new Response('Error', errorResponseInit)); + } +}); + +describe('checkConnection', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + test('should return true and log success message if the connection is successful', async () => { + jest.spyOn(console, 'log').mockImplementation((string) => string); + const result = await checkConnection('http://example.com/graphql/'); + + expect(result).toBe(true); + expect(console.log).toHaveBeenCalledWith( + '\nChecking Talawa-API connection....', + ); + expect(console.log).toHaveBeenCalledWith( + '\nConnection to Talawa-API successful! 🎉', + ); + }); + + it('should return false and log error message if the connection fails', async () => { + jest.spyOn(console, 'log').mockImplementation((string) => string); + const result = await checkConnection( + 'http://example_not_working.com/graphql/', + ); + + expect(result).toBe(false); + expect(console.log).toHaveBeenCalledWith( + '\nChecking Talawa-API connection....', + ); + expect(console.log).toHaveBeenCalledWith( + '\nTalawa-API service is unavailable. Is it running? Check your network connectivity too.', + ); + }); +}); diff --git a/src/setup/checkConnection/checkConnection.ts b/src/setup/checkConnection/checkConnection.ts new file mode 100644 index 0000000000..601bea98ca --- /dev/null +++ b/src/setup/checkConnection/checkConnection.ts @@ -0,0 +1,15 @@ +export async function checkConnection(url: string): Promise { + console.log('\nChecking Talawa-API connection....'); + let isConnected = false; + await fetch(url) + .then(() => { + isConnected = true; + console.log('\nConnection to Talawa-API successful! 🎉'); + }) + .catch(() => { + console.log( + '\nTalawa-API service is unavailable. Is it running? Check your network connectivity too.', + ); + }); + return isConnected; +} diff --git a/src/setup/checkEnvFile/checkEnvFile.test.ts b/src/setup/checkEnvFile/checkEnvFile.test.ts new file mode 100644 index 0000000000..a23976db4a --- /dev/null +++ b/src/setup/checkEnvFile/checkEnvFile.test.ts @@ -0,0 +1,47 @@ +import fs from 'fs'; +import { checkEnvFile } from './checkEnvFile'; + +jest.mock('fs'); + +describe('checkEnvFile', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('should append missing keys to the .env file', () => { + const envContent = 'EXISTING_KEY=existing_value\n'; + const envExampleContent = + 'EXISTING_KEY=existing_value\nNEW_KEY=default_value\n'; + + jest + .spyOn(fs, 'readFileSync') + .mockReturnValueOnce(envContent) + .mockReturnValueOnce(envExampleContent) + .mockReturnValueOnce(envExampleContent); + + jest.spyOn(fs, 'appendFileSync'); + + checkEnvFile(); + + expect(fs.appendFileSync).toHaveBeenCalledWith( + '.env', + 'NEW_KEY=default_value\n', + ); + }); + + it('should not append anything if all keys are present', () => { + const envContent = 'EXISTING_KEY=existing_value\n'; + const envExampleContent = 'EXISTING_KEY=existing_value\n'; + + jest + .spyOn(fs, 'readFileSync') + .mockReturnValueOnce(envContent) + .mockReturnValueOnce(envExampleContent); + + jest.spyOn(fs, 'appendFileSync'); + + checkEnvFile(); + + expect(fs.appendFileSync).not.toHaveBeenCalled(); + }); +}); diff --git a/src/setup/checkEnvFile/checkEnvFile.ts b/src/setup/checkEnvFile/checkEnvFile.ts new file mode 100644 index 0000000000..420a7c1321 --- /dev/null +++ b/src/setup/checkEnvFile/checkEnvFile.ts @@ -0,0 +1,16 @@ +import dotenv from 'dotenv'; +import fs from 'fs'; + +dotenv.config(); + +export function checkEnvFile(): void { + const env = dotenv.parse(fs.readFileSync('.env')); + const envSample = dotenv.parse(fs.readFileSync('.env.example')); + const misplaced = Object.keys(envSample).filter((key) => !(key in env)); + if (misplaced.length > 0) { + const config = dotenv.parse(fs.readFileSync('.env.example')); + misplaced.map((key) => + fs.appendFileSync('.env', `${key}=${config[key]}\n`), + ); + } +} diff --git a/src/setup/validateRecaptcha/validateRecaptcha.test.ts b/src/setup/validateRecaptcha/validateRecaptcha.test.ts new file mode 100644 index 0000000000..c77c9ed62b --- /dev/null +++ b/src/setup/validateRecaptcha/validateRecaptcha.test.ts @@ -0,0 +1,23 @@ +import { validateRecaptcha } from './validateRecaptcha'; + +describe('validateRecaptcha', () => { + it('should return true for a valid Recaptcha string', () => { + const validRecaptcha = 'ss7BEe32HPoDKTPXQevFkVvpvPzGebE2kIRv1ok4'; + expect(validateRecaptcha(validRecaptcha)).toBe(true); + }); + + it('should return false for an invalid Recaptcha string with special characters', () => { + const invalidRecaptcha = 'invalid@recaptcha!'; + expect(validateRecaptcha(invalidRecaptcha)).toBe(false); + }); + + it('should return false for an invalid Recaptcha string with incorrect length', () => { + const invalidRecaptcha = 'shortstring'; + expect(validateRecaptcha(invalidRecaptcha)).toBe(false); + }); + + it('should return false for an invalid Recaptcha string with spaces', () => { + const invalidRecaptcha = 'invalid recaptcha string'; + expect(validateRecaptcha(invalidRecaptcha)).toBe(false); + }); +}); diff --git a/src/setup/validateRecaptcha/validateRecaptcha.ts b/src/setup/validateRecaptcha/validateRecaptcha.ts new file mode 100644 index 0000000000..dcefb860fe --- /dev/null +++ b/src/setup/validateRecaptcha/validateRecaptcha.ts @@ -0,0 +1,4 @@ +export function validateRecaptcha(string: string): boolean { + const pattern = /^[a-zA-Z0-9_-]{40}$/; + return pattern.test(string); +} diff --git a/src/setupTests.ts b/src/setupTests.ts index 8f2609b7b3..eac7093309 100644 --- a/src/setupTests.ts +++ b/src/setupTests.ts @@ -3,3 +3,33 @@ // expect(element).toHaveTextContent(/react/i) // learn more: https://github.com/testing-library/jest-dom import '@testing-library/jest-dom'; + +global.fetch = jest.fn(); + +import { format } from 'util'; + +global.console.error = function (...args): void { + throw new Error(format(...args)); +}; + +global.console.warn = function (...args): void { + throw new Error(format(...args)); +}; +Object.defineProperty(HTMLMediaElement.prototype, 'muted', { + set: () => ({}), +}); + +import { jestPreviewConfigure } from 'jest-preview'; + +// Global CSS here +import 'bootstrap/dist/css/bootstrap.css'; +import 'bootstrap/dist/js/bootstrap.min.js'; +import 'react-datepicker/dist/react-datepicker.css'; +import 'flag-icons/css/flag-icons.min.css'; + +jestPreviewConfigure({ + // Opt-in to automatic mode to preview failed test case automatically. + autoPreview: true, +}); + +jest.setTimeout(15000); diff --git a/src/state/action-creators/index.test.ts b/src/state/action-creators/index.test.ts new file mode 100644 index 0000000000..33aa642b8a --- /dev/null +++ b/src/state/action-creators/index.test.ts @@ -0,0 +1,47 @@ +import { + updateInstalled, + installPlugin, + removePlugin, + updatePluginLinks, +} from './index'; +describe('Testing rc/state/action-creators/index.ts', () => { + test('updateInstalled Should call the dispatch function provided', () => { + //checking if the updateInstalled returns a valid function or not + const temp = updateInstalled('testPlug'); + expect(typeof temp).toBe('function'); + //stubbing the childfunction to check execution + const childFunction = jest.fn(); + temp(childFunction); + expect(childFunction).toHaveBeenCalled(); + }); + + test('installPlugin Should call the dispatch function provided', () => { + //checking if the installPlugin returns a valid function or not + const temp = installPlugin('testPlug'); + expect(typeof temp).toBe('function'); + //stubbing the childfunction to check execution + const childFunction = jest.fn(); + temp(childFunction); + expect(childFunction).toHaveBeenCalled(); + }); + + test('removePlugin Should call the dispatch function provided', () => { + //checking if the removePlugin returns a valid function or not + const temp = removePlugin('testPlug'); + expect(typeof temp).toBe('function'); + //stubbing the childfunction to check execution + const childFunction = jest.fn(); + temp(childFunction); + expect(childFunction).toHaveBeenCalled(); + }); + + test('updatePluginLinks Should call the dispatch function provided', () => { + //checking if the updatePluginLinks returns a valid function or not + const temp = updatePluginLinks('testPlug'); + expect(typeof temp).toBe('function'); + //stubbing the childfunction to check execution + const childFunction = jest.fn(); + temp(childFunction); + expect(childFunction).toHaveBeenCalled(); + }); +}); diff --git a/src/state/action-creators/index.ts b/src/state/action-creators/index.ts new file mode 100644 index 0000000000..7fb06971c5 --- /dev/null +++ b/src/state/action-creators/index.ts @@ -0,0 +1,44 @@ +export const updateInstalled = (plugin: any) => { + return (dispatch: any): void => { + dispatch({ + type: 'UPDATE_INSTALLED', + payload: plugin, + }); + }; +}; + +export const installPlugin = (plugin: any) => { + return (dispatch: any): void => { + dispatch({ + type: 'INSTALL_PLUGIN', + payload: plugin, + }); + }; +}; + +export const removePlugin = (plugin: any) => { + return (dispatch: any): void => { + dispatch({ + type: 'REMOVE_PLUGIN', + payload: plugin, + }); + }; +}; + +export const updatePluginLinks = (plugins: any) => { + return (dispatch: any): void => { + dispatch({ + type: 'UPDATE_P_TARGETS', + payload: plugins, + }); + }; +}; + +export const updateTargets = (orgId: string | undefined) => { + return (dispatch: any): void => { + dispatch({ + type: 'UPDATE_TARGETS', + payload: orgId, + }); + }; +}; diff --git a/src/state/helpers/Action.test.ts b/src/state/helpers/Action.test.ts new file mode 100644 index 0000000000..a971c6c160 --- /dev/null +++ b/src/state/helpers/Action.test.ts @@ -0,0 +1,8 @@ +import type { InterfaceAction } from './Action'; + +test('Testing Reducer Action Interface', () => { + ({ + type: 'STRING_ACTION_TYPE', + payload: 'ANY_PAYLOAD', + }) as InterfaceAction; +}); diff --git a/src/state/helpers/Action.ts b/src/state/helpers/Action.ts new file mode 100644 index 0000000000..469612441f --- /dev/null +++ b/src/state/helpers/Action.ts @@ -0,0 +1,4 @@ +export interface InterfaceAction { + type: string; + payload: any; +} diff --git a/src/state/index.ts b/src/state/index.ts new file mode 100644 index 0000000000..f35a3d6d46 --- /dev/null +++ b/src/state/index.ts @@ -0,0 +1 @@ +export * as actionCreators from './action-creators/index'; diff --git a/src/state/reducers/index.ts b/src/state/reducers/index.ts new file mode 100644 index 0000000000..ca2b2b28ee --- /dev/null +++ b/src/state/reducers/index.ts @@ -0,0 +1,12 @@ +import { combineReducers } from 'redux'; +import routesReducer from './routesReducer'; +import pluginReducer from './pluginReducer'; +import userRoutesReducer from './userRoutesReducer'; + +export const reducers = combineReducers({ + appRoutes: routesReducer, + plugins: pluginReducer, + userRoutes: userRoutesReducer, +}); + +export type RootState = ReturnType; diff --git a/src/state/reducers/pluginReducer.test.ts b/src/state/reducers/pluginReducer.test.ts new file mode 100644 index 0000000000..571345ce2f --- /dev/null +++ b/src/state/reducers/pluginReducer.test.ts @@ -0,0 +1,102 @@ +import reducer from './pluginReducer'; +import expect from 'expect'; + +describe('Testing Plugin Reducer', () => { + it('should return the initial state', () => { + expect( + reducer(undefined, { + type: '', + payload: undefined, + }), + ).toEqual({ + installed: [], + addonStore: [], + extras: [], + }); + }); + it('should handle INSTALL_PLUGIN', () => { + expect( + reducer( + { installed: [], addonStore: [], extras: [] }, + { + type: 'INSTALL_PLUGIN', + payload: { name: 'testplug' }, + }, + ), + ).toEqual({ + installed: [{ name: 'testplug' }], + addonStore: [], + extras: [], + }); + }); + it('should handle REMOVE_PLUGIN', () => { + expect( + reducer( + { + installed: [ + { name: 'testplug2', id: 3 }, + { name: 'testplug3', id: 5 }, + ], + addonStore: [], + extras: [], + }, + { + type: 'REMOVE_PLUGIN', + payload: { id: 3 }, + }, + ), + ).toEqual({ + installed: [{ name: 'testplug3', id: 5 }], + addonStore: [], + extras: [], + }); + }); + it('should handle UPDATE_INSTALLED', () => { + expect( + reducer( + { installed: [], addonStore: [], extras: [] }, + { + type: 'UPDATE_INSTALLED', + //Here payload is expected to be as array + payload: [{ name: 'testplug-updated' }], + }, + ), + ).toEqual({ + installed: [{ name: 'testplug-updated' }], + addonStore: [], + extras: [], + }); + }); + it('should handle UPDATE_STORE', () => { + expect( + reducer( + { installed: [], addonStore: [], extras: [] }, + { + type: 'UPDATE_STORE', + //Here payload is expected to be as array + payload: [{ name: 'sample-addon' }], + }, + ), + ).toEqual({ + installed: [], + addonStore: [{ name: 'sample-addon' }], + extras: [], + }); + }); + it('should handle UPDATE_EXTRAS', () => { + expect( + reducer( + { installed: [], addonStore: [], extras: [] }, + { + type: 'UPDATE_EXTRAS', + //Here payload is expected to be as array + payload: [{ name: 'sample-addon-extra' }], + }, + ), + ).toEqual({ + installed: [], + addonStore: [{ name: 'sample-addon-extra' }], + extras: [], + }); + }); +}); diff --git a/src/state/reducers/pluginReducer.ts b/src/state/reducers/pluginReducer.ts new file mode 100644 index 0000000000..192c995182 --- /dev/null +++ b/src/state/reducers/pluginReducer.ts @@ -0,0 +1,43 @@ +import type { InterfaceAction } from 'state/helpers/Action'; + +const reducer = ( + state = INITIAL_STATE, + action: InterfaceAction, +): typeof INITIAL_STATE => { + switch (action.type) { + case 'UPDATE_INSTALLED': + return Object.assign({}, state, { + installed: [...action.payload], + }); + case 'INSTALL_PLUGIN': + return Object.assign({}, state, { + installed: [...state.installed, action.payload], + }); + case 'REMOVE_PLUGIN': + return Object.assign({}, state, { + installed: [ + ...state.installed.filter( + (plugin: any) => plugin.id !== action.payload.id, + ), + ], + }); + case 'UPDATE_STORE': + return Object.assign({}, state, { + addonStore: [...action.payload], + }); + case 'UPDATE_EXTRAS': + return Object.assign({}, state, { + addonStore: [...action.payload], + }); + default: + return state; + } +}; + +const INITIAL_STATE: any = { + installed: [], + addonStore: [], + extras: [], +}; + +export default reducer; diff --git a/src/state/reducers/routesReducer.test.ts b/src/state/reducers/routesReducer.test.ts new file mode 100644 index 0000000000..84427ee4d0 --- /dev/null +++ b/src/state/reducers/routesReducer.test.ts @@ -0,0 +1,333 @@ +import expect from 'expect'; +import reducer from './routesReducer'; + +describe('Testing Routes reducer', () => { + it('should return the initial state', () => { + expect( + reducer(undefined, { + type: '', + payload: undefined, + }), + ).toEqual({ + targets: [ + { name: 'My Organizations', url: '/orglist' }, + { name: 'Dashboard', url: '/orgdash/undefined' }, + { name: 'People', url: '/orgpeople/undefined' }, + { name: 'Events', url: '/orgevents/undefined' }, + { name: 'Venues', url: '/orgvenues/undefined' }, + { name: 'Action Items', url: '/orgactionitems/undefined' }, + { name: 'Agenda Items Category', url: '/orgagendacategory/undefined' }, + { name: 'Posts', url: '/orgpost/undefined' }, + { + name: 'Block/Unblock', + url: '/blockuser/undefined', + }, + { name: 'Advertisement', url: '/orgads/undefined' }, + { name: 'Funds', url: '/orgfunds/undefined' }, + { name: 'Membership Requests', url: '/requests/undefined' }, + { + name: 'Plugins', + subTargets: [ + { + icon: 'fa-store', + name: 'Plugin Store', + url: '/orgstore/undefined', + }, + ], + }, + { name: 'Settings', url: '/orgsetting/undefined' }, + ], + components: [ + { name: 'My Organizations', comp_id: 'orglist', component: 'OrgList' }, + { + name: 'Dashboard', + comp_id: 'orgdash', + component: 'OrganizationDashboard', + }, + { + name: 'People', + comp_id: 'orgpeople', + component: 'OrganizationPeople', + }, + { + name: 'Events', + comp_id: 'orgevents', + component: 'OrganizationEvents', + }, + { + name: 'Venues', + comp_id: 'orgvenues', + component: 'OrganizationVenues', + }, + { + name: 'Action Items', + comp_id: 'orgactionitems', + component: 'OrganizationActionItems', + }, + { + name: 'Agenda Items Category', + comp_id: 'orgagendacategory', + component: 'OrganizationAgendaCategory', + }, + { name: 'Posts', comp_id: 'orgpost', component: 'OrgPost' }, + { name: 'Block/Unblock', comp_id: 'blockuser', component: 'BlockUser' }, + { + name: 'Advertisement', + comp_id: 'orgads', + component: 'Advertisements', + }, + { + name: 'Funds', + comp_id: 'orgfunds', + component: 'OrganizationFunds', + }, + { + name: 'Membership Requests', + comp_id: 'requests', + component: 'Requests', + }, + { + name: 'Plugins', + comp_id: null, + component: 'AddOnStore', + subTargets: [ + { + comp_id: 'orgstore', + component: 'AddOnStore', + icon: 'fa-store', + name: 'Plugin Store', + }, + ], + }, + { name: 'Settings', comp_id: 'orgsetting', component: 'OrgSettings' }, + { name: '', comp_id: 'member', component: 'MemberDetail' }, + ], + }); + }); + + it('should handle UPDATE_TARGETS', () => { + expect( + reducer(undefined, { + type: 'UPDATE_TARGETS', + payload: 'orgId', + }), + ).toEqual({ + targets: [ + { name: 'My Organizations', url: '/orglist' }, + { name: 'Dashboard', url: '/orgdash/orgId' }, + { name: 'People', url: '/orgpeople/orgId' }, + { name: 'Events', url: '/orgevents/orgId' }, + { name: 'Venues', url: '/orgvenues/orgId' }, + { name: 'Action Items', url: '/orgactionitems/orgId' }, + { name: 'Agenda Items Category', url: '/orgagendacategory/orgId' }, + { name: 'Posts', url: '/orgpost/orgId' }, + { name: 'Block/Unblock', url: '/blockuser/orgId' }, + { name: 'Advertisement', url: '/orgads/orgId' }, + { name: 'Funds', url: '/orgfunds/orgId' }, + { name: 'Membership Requests', url: '/requests/orgId' }, + { + name: 'Plugins', + subTargets: [ + { + icon: 'fa-store', + name: 'Plugin Store', + url: '/orgstore/orgId', + }, + ], + }, + { name: 'Settings', url: '/orgsetting/orgId' }, + ], + components: [ + { name: 'My Organizations', comp_id: 'orglist', component: 'OrgList' }, + { + name: 'Dashboard', + comp_id: 'orgdash', + component: 'OrganizationDashboard', + }, + { + name: 'People', + comp_id: 'orgpeople', + component: 'OrganizationPeople', + }, + { + name: 'Events', + comp_id: 'orgevents', + component: 'OrganizationEvents', + }, + { + name: 'Venues', + comp_id: 'orgvenues', + component: 'OrganizationVenues', + }, + { + name: 'Action Items', + comp_id: 'orgactionitems', + component: 'OrganizationActionItems', + }, + { + name: 'Agenda Items Category', + comp_id: 'orgagendacategory', + component: 'OrganizationAgendaCategory', + }, + { name: 'Posts', comp_id: 'orgpost', component: 'OrgPost' }, + { name: 'Block/Unblock', comp_id: 'blockuser', component: 'BlockUser' }, + { + name: 'Advertisement', + comp_id: 'orgads', + component: 'Advertisements', + }, + { name: 'Funds', comp_id: 'orgfunds', component: 'OrganizationFunds' }, + { + name: 'Membership Requests', + comp_id: 'requests', + component: 'Requests', + }, + { + name: 'Plugins', + comp_id: null, + component: 'AddOnStore', + subTargets: [ + { + comp_id: 'orgstore', + component: 'AddOnStore', + icon: 'fa-store', + name: 'Plugin Store', + }, + ], + }, + { name: 'Settings', comp_id: 'orgsetting', component: 'OrgSettings' }, + { name: '', comp_id: 'member', component: 'MemberDetail' }, + ], + }); + }); + + it('should handle UPDATE_P_TARGETS', () => { + expect( + reducer(undefined, { + type: 'UPDATE_P_TARGETS', + payload: [{ name: 'test-target-plugin', content: 'plugin-new' }], + }), + ).toEqual({ + targets: [ + { name: 'My Organizations', url: '/orglist' }, + { name: 'Dashboard', url: '/orgdash/undefined' }, + { name: 'People', url: '/orgpeople/undefined' }, + { name: 'Events', url: '/orgevents/undefined' }, + { name: 'Venues', url: '/orgvenues/undefined' }, + { name: 'Action Items', url: '/orgactionitems/undefined' }, + { name: 'Agenda Items Category', url: '/orgagendacategory/undefined' }, + { name: 'Posts', url: '/orgpost/undefined' }, + { + name: 'Block/Unblock', + url: '/blockuser/undefined', + }, + { name: 'Advertisement', url: '/orgads/undefined' }, + { name: 'Funds', url: '/orgfunds/undefined' }, + { name: 'Membership Requests', url: '/requests/undefined' }, + { name: 'Settings', url: '/orgsetting/undefined' }, + { + comp_id: null, + component: null, + name: 'Plugins', + subTargets: [ + { name: 'test-target-plugin', content: 'plugin-new' }, + { + icon: 'fa-store', + name: 'Plugin Store', + url: '/orgstore/undefined', + }, + ], + }, + ], + components: [ + { name: 'My Organizations', comp_id: 'orglist', component: 'OrgList' }, + { + name: 'Dashboard', + comp_id: 'orgdash', + component: 'OrganizationDashboard', + }, + { + name: 'People', + comp_id: 'orgpeople', + component: 'OrganizationPeople', + }, + { + name: 'Events', + comp_id: 'orgevents', + component: 'OrganizationEvents', + }, + { + name: 'Venues', + comp_id: 'orgvenues', + component: 'OrganizationVenues', + }, + { + name: 'Action Items', + comp_id: 'orgactionitems', + component: 'OrganizationActionItems', + }, + { + name: 'Agenda Items Category', + comp_id: 'orgagendacategory', + component: 'OrganizationAgendaCategory', + }, + { name: 'Posts', comp_id: 'orgpost', component: 'OrgPost' }, + { name: 'Block/Unblock', comp_id: 'blockuser', component: 'BlockUser' }, + { + name: 'Advertisement', + comp_id: 'orgads', + component: 'Advertisements', + }, + { + name: 'Funds', + comp_id: 'orgfunds', + component: 'OrganizationFunds', + }, + { + name: 'Membership Requests', + comp_id: 'requests', + component: 'Requests', + }, + { + name: 'Plugins', + comp_id: null, + component: 'AddOnStore', + subTargets: [ + { + comp_id: 'orgstore', + component: 'AddOnStore', + icon: 'fa-store', + name: 'Plugin Store', + }, + ], + }, + { name: 'Settings', comp_id: 'orgsetting', component: 'OrgSettings' }, + { name: '', comp_id: 'member', component: 'MemberDetail' }, + ], + }); + }); +}); + +describe('routesReducer', () => { + it('returns state with updated subTargets when UPDATE_P_TARGETS action is dispatched', () => { + const action = { + type: 'UPDATE_P_TARGETS', + payload: [{ name: 'New Plugin', url: '/newplugin' }], + }; + const initialState = { + targets: [{ name: 'Plugins' }], + components: [], + }; + const state = reducer(initialState, action); + const pluginsTarget = state.targets.find( + (target) => target.name === 'Plugins', + ); + // Check if pluginsTarget is defined + if (!pluginsTarget) { + throw new Error('Plugins target not found in state'); + } + expect(pluginsTarget.subTargets).toEqual([ + { name: 'New Plugin', url: '/newplugin' }, + ]); + }); +}); diff --git a/src/state/reducers/routesReducer.ts b/src/state/reducers/routesReducer.ts new file mode 100644 index 0000000000..bcda9f02d8 --- /dev/null +++ b/src/state/reducers/routesReducer.ts @@ -0,0 +1,143 @@ +import type { InterfaceAction } from 'state/helpers/Action'; + +export type TargetsType = { + name: string; + url?: string; + subTargets?: SubTargetType[]; +}; + +export type SubTargetType = { + name?: string; + url: string; + icon?: string; + comp_id?: string; +}; + +const reducer = ( + state = INITIAL_STATE, + action: InterfaceAction, +): typeof INITIAL_STATE => { + switch (action.type) { + case 'UPDATE_TARGETS': { + return Object.assign({}, state, { + targets: [...generateRoutes(components, action.payload)], + }); + } + case 'UPDATE_P_TARGETS': { + const filteredTargets = state.targets.filter( + (target: TargetsType) => target.name === 'Plugins', + ); + + const oldTargets: SubTargetType[] = filteredTargets[0]?.subTargets || []; + return Object.assign({}, state, { + targets: [ + ...state.targets.filter( + (target: TargetsType) => target.name !== 'Plugins', + ), + Object.assign( + {}, + { + name: 'Plugins', + comp_id: null, + component: null, + subTargets: [...action.payload, ...oldTargets], + }, + ), + ], + }); + } + default: { + return state; + } + } +}; + +export type ComponentType = { + name: string; + comp_id: string | null; + component: string | null; + subTargets?: { + name: string; + comp_id: string; + component: string; + icon?: string; + }[]; +}; + +// Note: Routes with names appear on NavBar +const components: ComponentType[] = [ + { name: 'My Organizations', comp_id: 'orglist', component: 'OrgList' }, + { name: 'Dashboard', comp_id: 'orgdash', component: 'OrganizationDashboard' }, + { name: 'People', comp_id: 'orgpeople', component: 'OrganizationPeople' }, + { name: 'Events', comp_id: 'orgevents', component: 'OrganizationEvents' }, + { name: 'Venues', comp_id: 'orgvenues', component: 'OrganizationVenues' }, + { + name: 'Action Items', + comp_id: 'orgactionitems', + component: 'OrganizationActionItems', + }, + { + name: 'Agenda Items Category', + comp_id: 'orgagendacategory', + component: 'OrganizationAgendaCategory', + }, + { name: 'Posts', comp_id: 'orgpost', component: 'OrgPost' }, + { name: 'Block/Unblock', comp_id: 'blockuser', component: 'BlockUser' }, + { name: 'Advertisement', comp_id: 'orgads', component: 'Advertisements' }, + { name: 'Funds', comp_id: 'orgfunds', component: 'OrganizationFunds' }, + { name: 'Membership Requests', comp_id: 'requests', component: 'Requests' }, + { + name: 'Plugins', + comp_id: null, + component: 'AddOnStore', // Default + subTargets: [ + { + name: 'Plugin Store', + comp_id: 'orgstore', + component: 'AddOnStore', + icon: 'fa-store', + }, + ], + }, + { name: 'Settings', comp_id: 'orgsetting', component: 'OrgSettings' }, + { name: '', comp_id: 'member', component: 'MemberDetail' }, +]; + +const generateRoutes = ( + comps: ComponentType[], + currentOrg = undefined, +): TargetsType[] => { + return comps + .filter((comp) => comp.name && comp.name !== '') + .map((comp) => { + const entry: TargetsType = comp.comp_id + ? comp.comp_id === 'orglist' + ? { name: comp.name, url: `/${comp.comp_id}` } + : { name: comp.name, url: `/${comp.comp_id}/${currentOrg}` } + : { + name: comp.name, + subTargets: comp.subTargets?.map( + (subTarget: { + name: string; + comp_id: string; + component: string; + icon?: string; + }) => { + return { + name: subTarget.name, + url: `/${subTarget.comp_id}/${currentOrg}`, + icon: subTarget.icon, + }; + }, + ), + }; + return entry; + }); +}; + +const INITIAL_STATE = { + targets: generateRoutes(components), + components, +}; + +export default reducer; diff --git a/src/state/reducers/userRoutersReducer.test.ts b/src/state/reducers/userRoutersReducer.test.ts new file mode 100644 index 0000000000..f819af8564 --- /dev/null +++ b/src/state/reducers/userRoutersReducer.test.ts @@ -0,0 +1,68 @@ +import expect from 'expect'; +import reducer from './userRoutesReducer'; + +describe('Testing Routes reducer', () => { + it('should return the initial state', () => { + expect( + reducer(undefined, { + type: '', + payload: undefined, + }), + ).toEqual({ + targets: [ + { name: 'My Organizations', url: 'user/organizations' }, + { name: 'Posts', url: 'user/organization/undefined' }, + { name: 'People', url: 'user/people/undefined' }, + { name: 'Events', url: 'user/events/undefined' }, + { name: 'Donate', url: 'user/donate/undefined' }, + ], + components: [ + { + name: 'My Organizations', + comp_id: 'organizations', + component: 'Organizations', + }, + { + name: 'Posts', + comp_id: 'organization', + component: 'Posts', + }, + { name: 'People', comp_id: 'people', component: 'People' }, + { name: 'Events', comp_id: 'events', component: 'Events' }, + { name: 'Donate', comp_id: 'donate', component: 'Donate' }, + ], + }); + }); + + it('should handle UPDATE_TARGETS', () => { + expect( + reducer(undefined, { + type: 'UPDATE_TARGETS', + payload: 'orgId', + }), + ).toEqual({ + targets: [ + { name: 'My Organizations', url: 'user/organizations' }, + { name: 'Posts', url: 'user/organization/orgId' }, + { name: 'People', url: 'user/people/orgId' }, + { name: 'Events', url: 'user/events/orgId' }, + { name: 'Donate', url: 'user/donate/orgId' }, + ], + components: [ + { + name: 'My Organizations', + comp_id: 'organizations', + component: 'Organizations', + }, + { + name: 'Posts', + comp_id: 'organization', + component: 'Posts', + }, + { name: 'People', comp_id: 'people', component: 'People' }, + { name: 'Events', comp_id: 'events', component: 'Events' }, + { name: 'Donate', comp_id: 'donate', component: 'Donate' }, + ], + }); + }); +}); diff --git a/src/state/reducers/userRoutesReducer.ts b/src/state/reducers/userRoutesReducer.ts new file mode 100644 index 0000000000..e85d4c25d9 --- /dev/null +++ b/src/state/reducers/userRoutesReducer.ts @@ -0,0 +1,81 @@ +import type { InterfaceAction } from 'state/helpers/Action'; + +export type TargetsType = { + name: string; + url?: string; + subTargets?: SubTargetType[]; +}; + +export type SubTargetType = { + name?: string; + url: string; + icon?: string; + comp_id?: string; +}; + +const reducer = ( + state = INITIAL_USER_STATE, + action: InterfaceAction, +): typeof INITIAL_USER_STATE => { + switch (action.type) { + case 'UPDATE_TARGETS': { + return Object.assign({}, state, { + targets: [...generateRoutes(components, action.payload)], + }); + } + default: { + return state; + } + } +}; + +export type ComponentType = { + name: string; + comp_id: string | null; + component: string | null; + subTargets?: { + name: string; + comp_id: string; + component: string; + icon?: string; + }[]; +}; + +// Note: Routes with names appear on NavBar +const components: ComponentType[] = [ + { + name: 'My Organizations', + comp_id: 'organizations', + component: 'Organizations', + }, + { + name: 'Posts', + comp_id: 'organization', + component: 'Posts', + }, + { name: 'People', comp_id: 'people', component: 'People' }, + { name: 'Events', comp_id: 'events', component: 'Events' }, + { name: 'Donate', comp_id: 'donate', component: 'Donate' }, +]; + +const generateRoutes = ( + comps: ComponentType[], + currentOrg = undefined, +): TargetsType[] => { + return comps + .filter((comp) => comp.name && comp.name !== '') + .map((comp) => { + const entry: TargetsType = + comp.comp_id === 'organizations' + ? { name: comp.name, url: `user/${comp.comp_id}` } + : { name: comp.name, url: `user/${comp.comp_id}/${currentOrg}` }; + return entry; + }); +}; + +const INITIAL_USER_STATE = { + targets: generateRoutes(components), + components, +}; + +export default reducer; diff --git a/src/state/store.test.tsx b/src/state/store.test.tsx new file mode 100644 index 0000000000..eedbbc84f0 --- /dev/null +++ b/src/state/store.test.tsx @@ -0,0 +1,27 @@ +import { store } from './store'; +describe('Testing src/state/store.ts', () => { + const state = store.getState(); + test('State should contain the properties appRoutes and plugins', () => { + expect(state).toHaveProperty('appRoutes'); + expect(state).toHaveProperty('plugins'); + }); + test('State schema should contain appRoutes and plugins', () => { + expect(state).toMatchObject({ + appRoutes: expect.any(Object), + plugins: expect.any(Object), + }); + }); + test('appRoutes schema should contain targets, configUrl and components', () => { + expect(state.appRoutes).toMatchObject({ + targets: expect.any(Array), + components: expect.any(Array), + }); + }); + test('plugins schema should contain installed, addOnStore and extras', () => { + expect(state.plugins).toMatchObject({ + installed: expect.any(Array), + addonStore: expect.any(Array), + extras: expect.any(Array), + }); + }); +}); diff --git a/src/state/store.ts b/src/state/store.ts new file mode 100644 index 0000000000..4ec777453a --- /dev/null +++ b/src/state/store.ts @@ -0,0 +1,5 @@ +import { applyMiddleware, createStore } from 'redux'; +import thunk from 'redux-thunk'; +import { reducers } from './reducers/index'; + +export const store = createStore(reducers, {}, applyMiddleware(thunk)); diff --git a/src/utils/StaticMockLink.ts b/src/utils/StaticMockLink.ts new file mode 100644 index 0000000000..31773d3978 --- /dev/null +++ b/src/utils/StaticMockLink.ts @@ -0,0 +1,176 @@ +import { print } from 'graphql'; +import { equal } from '@wry/equality'; +import { invariant } from 'ts-invariant'; + +import type { Operation, FetchResult } from '@apollo/client/link/core'; +import { ApolloLink } from '@apollo/client/link/core'; + +import { + Observable, + addTypenameToDocument, + removeClientSetsFromDocument, + removeConnectionDirectiveFromDocument, + cloneDeep, +} from '@apollo/client/utilities'; + +import type { MockedResponse, ResultFunction } from '@apollo/react-testing'; + +function requestToKey(request: any, addTypename: boolean): string { + const queryString = + request.query && + print(addTypename ? addTypenameToDocument(request.query) : request.query); + const requestKey = { query: queryString }; + return JSON.stringify(requestKey); +} + +/** + * Similar to the standard Apollo MockLink, but doesn't consume a mock + * when it is used allowing it to be used in places like Storybook. + */ +export class StaticMockLink extends ApolloLink { + public operation?: Operation; + public addTypename = true; + private _mockedResponsesByKey: { [key: string]: MockedResponse[] } = {}; + + constructor(mockedResponses: readonly MockedResponse[], addTypename = true) { + super(); + this.addTypename = addTypename; + if (mockedResponses) { + mockedResponses.forEach((mockedResponse) => { + this.addMockedResponse(mockedResponse); + }); + } + } + + public addMockedResponse(mockedResponse: MockedResponse): void { + const normalizedMockedResponse = + this._normalizeMockedResponse(mockedResponse); + const key = requestToKey( + normalizedMockedResponse.request, + this.addTypename, + ); + let mockedResponses = this._mockedResponsesByKey[key]; + if (!mockedResponses) { + mockedResponses = []; + this._mockedResponsesByKey[key] = mockedResponses; + } + mockedResponses.push(normalizedMockedResponse); + } + + public request(operation: any): Observable | null { + this.operation = operation; + const key = requestToKey(operation, this.addTypename); + let responseIndex = 0; + const response = (this._mockedResponsesByKey[key] || []).find( + (res, index) => { + const requestVariables = operation.variables || {}; + const mockedResponseVariables = res.request.variables || {}; + if (equal(requestVariables, mockedResponseVariables)) { + responseIndex = index; + return true; + } + return false; + }, + ); + + let configError: Error; + + if (!response || typeof responseIndex === 'undefined') { + configError = new Error( + `No more mocked responses for the query: ${print( + operation.query, + )}, variables: ${JSON.stringify(operation.variables)}`, + ); + } else { + const { newData } = response; + if (newData) { + response.result = newData(); + this._mockedResponsesByKey[key].push(response); + } + + if (!response.result && !response.error) { + configError = new Error( + `Mocked response should contain either result or error: ${key}`, + ); + } + } + + return new Observable((observer) => { + const timer = setTimeout( + () => { + if (configError) { + try { + // The onError function can return false to indicate that + // configError need not be passed to observer.error. For + // example, the default implementation of onError calls + // observer.error(configError) and then returns false to + // prevent this extra (harmless) observer.error call. + if (this.onError(configError, observer) !== false) { + throw configError; + } + } catch (error) { + observer.error(error); + } + } else if (response) { + if (response.error) { + observer.error(response.error); + } else { + if (response.result) { + observer.next( + typeof response.result === 'function' + ? (response.result as ResultFunction)() + : response.result, + ); + } + observer.complete(); + } + } + }, + (response && response.delay) || 0, + ); + + return () => { + clearTimeout(timer); + }; + }); + } + + private _normalizeMockedResponse( + mockedResponse: MockedResponse, + ): MockedResponse { + const newMockedResponse = cloneDeep(mockedResponse); + const queryWithoutConnection = removeConnectionDirectiveFromDocument( + newMockedResponse.request.query, + ); + invariant(queryWithoutConnection, 'query is required'); + newMockedResponse.request.query = queryWithoutConnection; + const query = removeClientSetsFromDocument(newMockedResponse.request.query); + if (query) { + newMockedResponse.request.query = query; + } + return newMockedResponse; + } +} + +export interface InterfaceMockApolloLink extends ApolloLink { + operation?: Operation; +} + +// Pass in multiple mocked responses, so that you can test flows that end up +// making multiple queries to the server. +// NOTE: The last arg can optionally be an `addTypename` arg. +export function mockSingleLink( + ...mockedResponses: any[] +): InterfaceMockApolloLink { + // To pull off the potential typename. If this isn't a boolean, we'll just + // set it true later. + let maybeTypename = mockedResponses[mockedResponses.length - 1]; + let mocks = mockedResponses.slice(0, mockedResponses.length - 1); + + if (typeof maybeTypename !== 'boolean') { + mocks = mockedResponses; + maybeTypename = true; + } + + return new StaticMockLink(mocks, maybeTypename); +} diff --git a/src/utils/convertToBase64.test.ts b/src/utils/convertToBase64.test.ts new file mode 100644 index 0000000000..51198ccc29 --- /dev/null +++ b/src/utils/convertToBase64.test.ts @@ -0,0 +1,33 @@ +import convertToBase64 from './convertToBase64'; + +describe('convertToBase64', () => { + it('should return a base64-encoded string when given a file', async () => { + const file = new File(['hello'], 'hello.txt', { type: 'text/plain' }); + const result = await convertToBase64(file); + expect(result).toMatch(/^data:text\/plain;base64,[a-zA-Z0-9+/]+={0,2}$/); + }); + + it('should return an empty string when given an invalid file', async () => { + const file = {} as File; + const result = await convertToBase64(file); + expect(result).toBe(''); + }); + + it('should handle errors thrown by FileReader', async () => { + // Arrange + const file = new File(['hello'], 'hello.txt', { type: 'text/plain' }); + const mockFileReader = jest + .spyOn(global, 'FileReader') + .mockImplementationOnce(() => { + throw new Error('Test error'); + }); + + // Act + const result = await convertToBase64(file); + + // Assert + expect(mockFileReader).toHaveBeenCalledTimes(1); + expect(mockFileReader).toHaveBeenCalledWith(); + expect(result).toBe(''); + }); +}); diff --git a/src/utils/convertToBase64.ts b/src/utils/convertToBase64.ts new file mode 100644 index 0000000000..2264d04d58 --- /dev/null +++ b/src/utils/convertToBase64.ts @@ -0,0 +1,15 @@ +const convertToBase64 = async (file: File): Promise => { + try { + const res = await new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = (): void => resolve(reader.result); + reader.onerror = (error): void => reject(error); + }); + return `${res}`; + } catch (error) { + return ''; + } +}; + +export default convertToBase64; diff --git a/src/utils/currency.ts b/src/utils/currency.ts new file mode 100644 index 0000000000..c7db3002f2 --- /dev/null +++ b/src/utils/currency.ts @@ -0,0 +1,330 @@ +export const currencyOptions = [ + { value: 'AED', label: 'AED' }, // United Arab Emirates Dirham + { value: 'AFN', label: 'AFN' }, // Afghan Afghani + { value: 'ALL', label: 'ALL' }, // Albanian Lek + { value: 'AMD', label: 'AMD' }, // Armenian Dram + { value: 'ANG', label: 'ANG' }, // Netherlands Antillean Guilder + { value: 'AOA', label: 'AOA' }, // Angolan Kwanza + { value: 'ARS', label: 'ARS' }, // Argentine Peso + { value: 'AUD', label: 'AUD' }, // Australian Dollar + { value: 'AWG', label: 'AWG' }, // Aruban Florin + { value: 'AZN', label: 'AZN' }, // Azerbaijani Manat + { value: 'BAM', label: 'BAM' }, // Bosnia-Herzegovina Convertible Mark + { value: 'BBD', label: 'BBD' }, // Barbadian Dollar + { value: 'BDT', label: 'BDT' }, // Bangladeshi Taka + { value: 'BGN', label: 'BGN' }, // Bulgarian Lev + { value: 'BHD', label: 'BHD' }, // Bahraini Dinar + { value: 'BIF', label: 'BIF' }, // Burundian Franc + { value: 'BMD', label: 'BMD' }, // Bermudian Dollar + { value: 'BND', label: 'BND' }, // Brunei Dollar + { value: 'BOB', label: 'BOB' }, // Bolivian Boliviano + { value: 'BRL', label: 'BRL' }, // Brazilian Real + { value: 'BSD', label: 'BSD' }, // Bahamian Dollar + { value: 'BTN', label: 'BTN' }, // Bhutanese Ngultrum + { value: 'BWP', label: 'BWP' }, // Botswanan Pula + { value: 'BYN', label: 'BYN' }, // Belarusian Ruble + { value: 'BZD', label: 'BZD' }, // Belize Dollar + { value: 'CAD', label: 'CAD' }, // Canadian Dollar + { value: 'CDF', label: 'CDF' }, // Congolese Franc + { value: 'CHF', label: 'CHF' }, // Swiss Franc + { value: 'CLP', label: 'CLP' }, // Chilean Peso + { value: 'CNY', label: 'CNY' }, // Chinese Yuan + { value: 'COP', label: 'COP' }, // Colombian Peso + { value: 'CRC', label: 'CRC' }, // Costa Rican Colón + { value: 'CUP', label: 'CUP' }, // Cuban Peso + { value: 'CVE', label: 'CVE' }, // Cape Verdean Escudo + { value: 'CZK', label: 'CZK' }, // Czech Koruna + { value: 'DJF', label: 'DJF' }, // Djiboutian Franc + { value: 'DKK', label: 'DKK' }, // Danish Krone + { value: 'DOP', label: 'DOP' }, // Dominican Peso + { value: 'DZD', label: 'DZD' }, // Algerian Dinar + { value: 'EGP', label: 'EGP' }, // Egyptian Pound + { value: 'ERN', label: 'ERN' }, // Eritrean Nakfa + { value: 'ETB', label: 'ETB' }, // Ethiopian Birr + { value: 'EUR', label: 'EUR' }, // Euro + { value: 'FJD', label: 'FJD' }, // Fijian Dollar + { value: 'FKP', label: 'FKP' }, // Falkland Islands Pound + { value: 'FOK', label: 'FOK' }, // Faroese Krona + { value: 'FRO', label: 'FRO' }, // Fijian Dollar + { value: 'GBP', label: 'GBP' }, // British Pound Sterling + { value: 'GEL', label: 'GEL' }, // Georgian Lari + { value: 'GGP', label: 'GGP' }, // Guernsey Pound + { value: 'GHS', label: 'GHS' }, // Ghanaian Cedi + { value: 'GIP', label: 'GIP' }, // Gibraltar Pound + { value: 'GMD', label: 'GMD' }, // Gambian Dalasi + { value: 'GNF', label: 'GNF' }, // Guinean Franc + { value: 'GTQ', label: 'GTQ' }, // Guatemalan Quetzal + { value: 'GYD', label: 'GYD' }, // Guyanaese Dollar + { value: 'HKD', label: 'HKD' }, // Hong Kong Dollar + { value: 'HNL', label: 'HNL' }, // Honduran Lempira + { value: 'HRK', label: 'HRK' }, // Croatian Kuna + { value: 'HTG', label: 'HTG' }, // Haitian Gourde + { value: 'HUF', label: 'HUF' }, // Hungarian Forint + { value: 'IDR', label: 'IDR' }, // Indonesian Rupiah + { value: 'ILS', label: 'ILS' }, // Israeli New Shekel + { value: 'IMP', label: 'IMP' }, // Manx pound + { value: 'INR', label: 'INR' }, // Indian Rupee + { value: 'IQD', label: 'IQD' }, // Iraqi Dinar + { value: 'IRR', label: 'IRR' }, // Iranian Rial + { value: 'ISK', label: 'ISK' }, // Icelandic Króna + { value: 'JEP', label: 'JEP' }, // Jersey Pound + { value: 'JMD', label: 'JMD' }, // Jamaican Dollar + { value: 'JOD', label: 'JOD' }, // Jordanian Dinar + { value: 'JPY', label: 'JPY' }, // Japanese Yen + { value: 'KES', label: 'KES' }, // Kenyan Shilling + { value: 'KGS', label: 'KGS' }, // Kyrgystani Som + { value: 'KHR', label: 'KHR' }, // Cambodian Riel + { value: 'KID', label: 'KID' }, // Kiribati dollar + { value: 'KMF', label: 'KMF' }, // Comorian Franc + { value: 'KRW', label: 'KRW' }, // South Korean Won + { value: 'KWD', label: 'KWD' }, // Kuwaiti Dinar + { value: 'KYD', label: 'KYD' }, // Cayman Islands Dollar + { value: 'KZT', label: 'KZT' }, // Kazakhstani Tenge + { value: 'LAK', label: 'LAK' }, // Laotian Kip + { value: 'LBP', label: 'LBP' }, // Lebanese Pound + { value: 'LKR', label: 'LKR' }, // Sri Lankan Rupee + { value: 'LRD', label: 'LRD' }, // Liberian Dollar + { value: 'LSL', label: 'LSL' }, // Lesotho Loti + { value: 'LYD', label: 'LYD' }, // Libyan Dinar + { value: 'MAD', label: 'MAD' }, // Moroccan Dirham + { value: 'MDL', label: 'MDL' }, // Moldovan Leu + { value: 'MGA', label: 'MGA' }, // Malagasy Ariary + { value: 'MKD', label: 'MKD' }, // Macedonian Denar + { value: 'MMK', label: 'MMK' }, // Myanma Kyat + { value: 'MNT', label: 'MNT' }, // Mongolian Tugrik + { value: 'MOP', label: 'MOP' }, // Macanese Pataca + { value: 'MRU', label: 'MRU' }, // Mauritanian Ouguiya + { value: 'MUR', label: 'MUR' }, // Mauritian Rupee + { value: 'MVR', label: 'MVR' }, // Maldivian Rufiyaa + { value: 'MWK', label: 'MWK' }, // Malawian Kwacha + { value: 'MXN', label: 'MXN' }, // Mexican Peso + { value: 'MYR', label: 'MYR' }, // Malaysian Ringgit + { value: 'MZN', label: 'MZN' }, // Mozambican Metical + { value: 'NAD', label: 'NAD' }, // Namibian Dollar + { value: 'NGN', label: 'NGN' }, // Nigerian Naira + { value: 'NIO', label: 'NIO' }, // Nicaraguan Córdoba + { value: 'NOK', label: 'NOK' }, // Norwegian Krone + { value: 'NPR', label: 'NPR' }, // Nepalese Rupee + { value: 'NZD', label: 'NZD' }, // New Zealand Dollar + { value: 'OMR', label: 'OMR' }, // Omani Rial + { value: 'PAB', label: 'PAB' }, // Panamanian Balboa + { value: 'PEN', label: 'PEN' }, // Peruvian Nuevo Sol + { value: 'PGK', label: 'PGK' }, // Papua New Guinean Kina + { value: 'PHP', label: 'PHP' }, // Philippine Peso + { value: 'PKR', label: 'PKR' }, // Pakistani Rupee + { value: 'PLN', label: 'PLN' }, // Polish Zloty + { value: 'PYG', label: 'PYG' }, // Paraguayan Guarani + { value: 'QAR', label: 'QAR' }, // Qatari Rial + { value: 'RON', label: 'RON' }, // Romanian Leu + { value: 'RSD', label: 'RSD' }, // Serbian Dinar + { value: 'RUB', label: 'RUB' }, // Russian Ruble + { value: 'RWF', label: 'RWF' }, // Rwandan Franc + { value: 'SAR', label: 'SAR' }, // Saudi Riyal + { value: 'SBD', label: 'SBD' }, // Solomon Islands Dollar + { value: 'SCR', label: 'SCR' }, // Seychellois Rupee + { value: 'SDG', label: 'SDG' }, // Sudanese Pound + { value: 'SEK', label: 'SEK' }, // Swedish Krona + { value: 'SGD', label: 'SGD' }, // Singapore Dollar + { value: 'SHP', label: 'SHP' }, // Saint Helena Pound + { value: 'SLL', label: 'SLL' }, // Sierra Leonean Leone + { value: 'SOS', label: 'SOS' }, // Somali Shilling + { value: 'SPL', label: 'SPL' }, // Seborgan Luigino + { value: 'SRD', label: 'SRD' }, // Surinamese Dollar + { value: 'STN', label: 'STN' }, // São Tomé and Príncipe Dobra + { value: 'SVC', label: 'SVC' }, // Salvadoran Colón + { value: 'SYP', label: 'SYP' }, // Syrian Pound + { value: 'SZL', label: 'SZL' }, // Swazi Lilangeni + { value: 'THB', label: 'THB' }, // Thai Baht + { value: 'TJS', label: 'TJS' }, // Tajikistani Somoni + { value: 'TMT', label: 'TMT' }, // Turkmenistani Manat + { value: 'TND', label: 'TND' }, // Tunisian Dinar + { value: 'TOP', label: 'TOP' }, // Tongan Pa'anga + { value: 'TRY', label: 'TRY' }, // Turkish Lira + { value: 'TTD', label: 'TTD' }, // Trinidad and Tobago Dollar + { value: 'TVD', label: 'TVD' }, // Tuvaluan Dollar + { value: 'TWD', label: 'TWD' }, // New Taiwan Dollar + { value: 'TZS', label: 'TZS' }, // Tanzanian Shilling + { value: 'UAH', label: 'UAH' }, // Ukrainian Hryvnia + { value: 'UGX', label: 'UGX' }, // Ugandan Shilling + { value: 'USD', label: 'USD' }, // United States Dollar + { value: 'UYU', label: 'UYU' }, // Uruguayan Peso + { value: 'UZS', label: 'UZS' }, // Uzbekistan Som + { value: 'VEF', label: 'VEF' }, // Venezuelan Bolívar + { value: 'VND', label: 'VND' }, // Vietnamese Dong + { value: 'VUV', label: 'VUV' }, // Vanuatu Vatu + { value: 'WST', label: 'WST' }, // Samoan Tala + { value: 'XAF', label: 'XAF' }, // CFA Franc BEAC + { value: 'XCD', label: 'XCD' }, // East Caribbean Dollar + { value: 'XDR', label: 'XDR' }, // Special Drawing Rights + { value: 'XOF', label: 'XOF' }, // CFA Franc BCEAO + { value: 'XPF', label: 'XPF' }, // CFP Franc + { value: 'YER', label: 'YER' }, // Yemeni Rial + { value: 'ZAR', label: 'ZAR' }, // South African Rand + { value: 'ZMW', label: 'ZMW' }, // Zambian Kwacha + { value: 'ZWD', label: 'ZWD' }, // Zimbabwean Dollar +]; +export const currencySymbols: { [key: string]: string } = { + AED: 'د.إ', // United Arab Emirates Dirham + AFN: '؋', // Afghan Afghani + ALL: 'L', // Albanian Lek + AMD: '֏', // Armenian Dram + ANG: 'ƒ', // Netherlands Antillean Guilder + AOA: 'Kz', // Angolan Kwanza + ARS: '$', // Argentine Peso + AUD: '$', // Australian Dollar + AWG: 'ƒ', // Aruban Florin + AZN: '₼', // Azerbaijani Manat + BAM: 'КМ', // Bosnia-Herzegovina Convertible Mark + BBD: '$', // Barbadian Dollar + BDT: '৳', // Bangladeshi Taka + BGN: 'лв', // Bulgarian Lev + BHD: '.د.ب', // Bahraini Dinar + BIF: 'FBu', // Burundian Franc + BMD: '$', // Bermudian Dollar + BND: '$', // Brunei Dollar + BOB: 'Bs.', // Bolivian Boliviano + BRL: 'R$', // Brazilian Real + BSD: '$', // Bahamian Dollar + BTN: 'Nu.', // Bhutanese Ngultrum + BWP: 'P', // Botswanan Pula + BYN: 'Br', // Belarusian Ruble + BZD: 'BZ$', // Belize Dollar + CAD: '$', // Canadian Dollar + CDF: 'FC', // Congolese Franc + CHF: 'CHF', // Swiss Franc + CLP: '$', // Chilean Peso + CNY: '¥', // Chinese Yuan + COP: '$', // Colombian Peso + CRC: '₡', // Costa Rican Colón + CUP: '₱', // Cuban Peso + CVE: '$', // Cape Verdean Escudo + CZK: 'Kč', // Czech Koruna + DJF: 'Fdj', // Djiboutian Franc + DKK: 'kr', // Danish Krone + DOP: 'RD$', // Dominican Peso + DZD: 'د.ج', // Algerian Dinar + EGP: 'ج.م', // Egyptian Pound + ERN: 'Nfk', // Eritrean Nakfa + ETB: 'ብር', // Ethiopian Birr + EUR: '€', // Euro + FJD: 'FJ$', // Fijian Dollar + FKP: '£', // Falkland Islands Pound + FOK: 'kr', // Faroese Krona + FRO: 'kr', // Fijian Dollar + GBP: '£', // British Pound Sterling + GEL: '₾', // Georgian Lari + GGP: '£', // Guernsey Pound + GHS: '₵', // Ghanaian Cedi + GIP: '£', // Gibraltar Pound + GMD: 'D', // Gambian Dalasi + GNF: 'FG', // Guinean Franc + GTQ: 'Q', // Guatemalan Quetzal + GYD: '$', // Guyanaese Dollar + HKD: '$', // Hong Kong Dollar + HNL: 'L', // Honduran Lempira + HRK: 'kn', // Croatian Kuna + HTG: 'G', // Haitian Gourde + HUF: 'Ft', // Hungarian Forint + IDR: 'Rp', // Indonesian Rupiah + ILS: '₪', // Israeli New Shekel + IMP: '£', // Manx pound + INR: '₹', // Indian Rupee + IQD: 'د.ع', // Iraqi Dinar + IRR: '﷼', // Iranian Rial + ISK: 'kr', // Icelandic Króna + JEP: '£', // Jersey Pound + JMD: 'J$', // Jamaican Dollar + JOD: 'د.ا', // Jordanian Dinar + JPY: '¥', // Japanese Yen + KES: 'KSh', // Kenyan Shilling + KGS: 'с', // Kyrgystani Som + KHR: '៛', // Cambodian Riel + KID: '$', // Kiribati dollar + KMF: 'CF', // Comorian Franc + KRW: '₩', // South Korean Won + KWD: 'د.ك', // Kuwaiti Dinar + KYD: '$', // Cayman Islands Dollar + KZT: '₸', // Kazakhstani Tenge + LAK: '₭', // Laotian Kip + LBP: 'ل.ل', // Lebanese Pound + LKR: 'රු', // Sri Lankan Rupee + LRD: '$', // Liberian Dollar + LSL: 'L', // Lesotho Loti + LYD: 'ل.د', // Libyan Dinar + MAD: 'د.م.', // Moroccan Dirham + MDL: 'L', // Moldovan Leu + MGA: 'Ar', // Malagasy Ariary + MKD: 'ден', // Macedonian Denar + MMK: 'K', // Myanma Kyat + MNT: '₮', // Mongolian Tugrik + MOP: 'MOP$', // Macanese Pataca + MRU: 'UM', // Mauritanian Ouguiya + MUR: '₨', // Mauritian Rupee + MVR: 'ރ.', // Maldivian Rufiyaa + MWK: 'MK', // Malawian Kwacha + MXN: '$', // Mexican Peso + MYR: 'RM', // Malaysian Ringgit + MZN: 'MT', // Mozambican Metical + NAD: '$', // Namibian Dollar + NGN: '₦', // Nigerian Naira + NIO: 'C$', // Nicaraguan Córdoba + NOK: 'kr', // Norwegian Krone + NPR: '₨', // Nepalese Rupee + NZD: '$', // New Zealand Dollar + OMR: 'ر.ع.', // Omani Rial + PAB: 'B/.', // Panamanian Balboa + PEN: 'S/', // Peruvian Nuevo Sol + PGK: 'K', // Papua New Guinean Kina + PHP: '₱', // Philippine Peso + PKR: '₨', // Pakistani Rupee + PLN: 'zł', // Polish Zloty + PYG: '₲', // Paraguayan Guarani + QAR: 'ر.ق', // Qatari Rial + RON: 'lei', // Romanian Leu + RSD: 'дин', // Serbian Dinar + RUB: '₽', // Russian Ruble + RWF: 'RF', // Rwandan Franc + SAR: 'ر.س', // Saudi Riyal + SBD: '$', // Solomon Islands Dollar + SCR: 'SR', // Seychellois Rupee + SDG: 'ج.س.', // Sudanese Pound + SEK: 'kr', // Swedish Krona + SGD: '$', // Singapore Dollar + SHP: '£', // Saint Helena Pound + SLL: 'Le', // Sierra Leonean Leone + SOS: 'Sh', // Somali Shilling + SPL: 'L', // Seborgan Luigino + SRD: '$', // Surinamese Dollar + STN: 'Db', // São Tomé and Príncipe Dobra + SVC: '₡', // Salvadoran Colón + SYP: '£S', // Syrian Pound + SZL: 'E', // Swazi Lilangeni + THB: '฿', // Thai Baht + TJS: 'ЅМ', // Tajikistani Somoni + TMT: 'T', // Turkmenistani Manat + TND: 'د.ت', // Tunisian Dinar + TOP: 'T$', // Tongan Pa'anga + TRY: '₺', // Turkish Lira + TTD: 'TT$', // Trinidad and Tobago Dollar + TVD: '$', // Tuvaluan Dollar + TWD: 'NT$', // New Taiwan Dollar + TZS: 'TSh', // Tanzanian Shilling + UAH: '₴', // Ukrainian Hryvnia + UGX: 'USh', // Ugandan Shilling + USD: '$', // United States Dollar + UYU: '$U', // Uruguayan Peso + UZS: 'UZS', // Uzbekistan Som + VEF: 'Bs.', // Venezuelan Bolívar + VND: '₫', // Vietnamese Dong + VUV: 'VT', // Vanuatu Vatu + WST: 'WS$', // Samoan Tala + XAF: 'FCFA', // CFA Franc BEAC + XCD: 'EC$', // East Caribbean Dollar + XDR: 'SDR', // Special Drawing Rights + XOF: 'CFA', // CFA Franc BCEAO + XPF: 'CFP', // CFP Franc + YER: '﷼', // Yemeni Rial + ZAR: 'R', // South African Rand + ZMW: 'ZK', // Zambian Kwacha + ZWD: 'Z$', // Zimbabwean Dollar +}; diff --git a/src/utils/errorHandler.test.tsx b/src/utils/errorHandler.test.tsx new file mode 100644 index 0000000000..1ca42441ab --- /dev/null +++ b/src/utils/errorHandler.test.tsx @@ -0,0 +1,37 @@ +import type { TFunction } from 'react-i18next'; +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<'translation', string> = (key: string) => key; + const tErrors: TFunction<'errors', string> = (key: string) => 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 new file mode 100644 index 0000000000..aa7c6dc9dc --- /dev/null +++ b/src/utils/errorHandler.tsx @@ -0,0 +1,23 @@ +import type { TFunction } from 'react-i18next'; +import { toast } from 'react-toastify'; +import i18n from './i18n'; +/* + This function is used to handle api errors in the application. + It takes in the error object and displays the error message to the user. + If the error is due to the Talawa API being unavailable, it displays a custom message. +*/ +export const errorHandler = (a: unknown, error: unknown): void => { + const tErrors: TFunction = i18n.getFixedT(null, 'errors'); + if (error instanceof Error) { + switch (error.message) { + case 'Failed to fetch': + toast.error(tErrors('talawaApiUnavailable')); + break; + // Add more cases as needed + default: + toast.error(error.message); + } + } else { + toast.error(tErrors('unknownError', { msg: error })); + } +}; diff --git a/src/utils/fieldTypes.ts b/src/utils/fieldTypes.ts new file mode 100644 index 0000000000..b17fb9833a --- /dev/null +++ b/src/utils/fieldTypes.ts @@ -0,0 +1,3 @@ +const availableFieldTypes = ['String', 'Boolean', 'Date', 'Number']; + +export default availableFieldTypes; diff --git a/src/utils/formEnumFields.ts b/src/utils/formEnumFields.ts new file mode 100644 index 0000000000..928537aaab --- /dev/null +++ b/src/utils/formEnumFields.ts @@ -0,0 +1,352 @@ +const countryOptions = [ + { value: 'af', label: 'Afghanistan' }, + { value: 'al', label: 'Albania' }, + { value: 'dz', label: 'Algeria' }, + { value: 'ad', label: 'Andorra' }, + { value: 'ao', label: 'Angola' }, + { value: 'ai', label: 'Anguilla' }, + { value: 'ag', label: 'Antigua and Barbuda' }, + { value: 'ar', label: 'Argentina' }, + { value: 'am', label: 'Armenia' }, + { value: 'aw', label: 'Aruba' }, + { value: 'au', label: 'Australia' }, + { value: 'at', label: 'Austria' }, + { value: 'az', label: 'Azerbaijan' }, + { value: 'bs', label: 'Bahamas' }, + { value: 'bh', label: 'Bahrain' }, + { value: 'bd', label: 'Bangladesh' }, + { value: 'bb', label: 'Barbados' }, + { value: 'by', label: 'Belarus' }, + { value: 'be', label: 'Belgium' }, + { value: 'bz', label: 'Belize' }, + { value: 'bj', label: 'Benin' }, + { value: 'bm', label: 'Bermuda' }, + { value: 'bt', label: 'Bhutan' }, + { value: 'bo', label: 'Bolivia' }, + { value: 'ba', label: 'Bosnia and Herzegovina' }, + { value: 'bw', label: 'Botswana' }, + { value: 'br', label: 'Brazil' }, + { value: 'bn', label: 'Brunei' }, + { value: 'bg', label: 'Bulgaria' }, + { value: 'bf', label: 'Burkina Faso' }, + { value: 'bi', label: 'Burundi' }, + { value: 'cv', label: 'Cabo Verde' }, + { value: 'kh', label: 'Cambodia' }, + { value: 'cm', label: 'Cameroon' }, + { value: 'ca', label: 'Canada' }, + { value: 'ky', label: 'Cayman Islands' }, + { value: 'cf', label: 'Central African Republic' }, + { value: 'td', label: 'Chad' }, + { value: 'cl', label: 'Chile' }, + { value: 'cn', label: 'China' }, + { value: 'co', label: 'Colombia' }, + { value: 'km', label: 'Comoros' }, + { value: 'cg', label: 'Congo' }, + { value: 'cr', label: 'Costa Rica' }, + { value: 'hr', label: 'Croatia' }, + { value: 'cu', label: 'Cuba' }, + { value: 'cy', label: 'Cyprus' }, + { value: 'cz', label: 'Czechia' }, + { value: 'dk', label: 'Denmark' }, + { value: 'dj', label: 'Djibouti' }, + { value: 'dm', label: 'Dominica' }, + { value: 'do', label: 'Dominican Republic' }, + { value: 'ec', label: 'Ecuador' }, + { value: 'eg', label: 'Egypt' }, + { value: 'sv', label: 'El Salvador' }, + { value: 'gq', label: 'Equatorial Guinea' }, + { value: 'er', label: 'Eritrea' }, + { value: 'ee', label: 'Estonia' }, + { value: 'et', label: 'Ethiopia' }, + { value: 'fj', label: 'Fiji' }, + { value: 'fi', label: 'Finland' }, + { value: 'fr', label: 'France' }, + { value: 'ga', label: 'Gabon' }, + { value: 'gm', label: 'Gambia' }, + { value: 'ge', label: 'Georgia' }, + { value: 'de', label: 'Germany' }, + { value: 'gh', label: 'Ghana' }, + { value: 'gi', label: 'Gibraltar' }, + { value: 'gr', label: 'Greece' }, + { value: 'gl', label: 'Greenland' }, + { value: 'gd', label: 'Grenada' }, + { value: 'gt', label: 'Guatemala' }, + { value: 'gn', label: 'Guinea' }, + { value: 'gw', label: 'Guinea-Bissau' }, + { value: 'gy', label: 'Guyana' }, + { value: 'ht', label: 'Haiti' }, + { value: 'hn', label: 'Honduras' }, + { value: 'hu', label: 'Hungary' }, + { value: 'is', label: 'Iceland' }, + { value: 'in', label: 'India' }, + { value: 'id', label: 'Indonesia' }, + { value: 'ir', label: 'Iran' }, + { value: 'iq', label: 'Iraq' }, + { value: 'ie', label: 'Ireland' }, + { value: 'il', label: 'Israel' }, + { value: 'it', label: 'Italy' }, + { value: 'jm', label: 'Jamaica' }, + { value: 'jp', label: 'Japan' }, + { value: 'jo', label: 'Jordan' }, + { value: 'kz', label: 'Kazakhstan' }, + { value: 'ke', label: 'Kenya' }, + { value: 'ki', label: 'Kiribati' }, + { value: 'kw', label: 'Kuwait' }, + { value: 'kg', label: 'Kyrgyzstan' }, + { value: 'la', label: 'Laos' }, + { value: 'lv', label: 'Latvia' }, + { value: 'lb', label: 'Lebanon' }, + { value: 'ls', label: 'Lesotho' }, + { value: 'lr', label: 'Liberia' }, + { value: 'ly', label: 'Libya' }, + { value: 'li', label: 'Liechtenstein' }, + { value: 'lt', label: 'Lithuania' }, + { value: 'lu', label: 'Luxembourg' }, + { value: 'mk', label: 'North Macedonia' }, + { value: 'mg', label: 'Madagascar' }, + { value: 'mw', label: 'Malawi' }, + { value: 'my', label: 'Malaysia' }, + { value: 'mv', label: 'Maldives' }, + { value: 'ml', label: 'Mali' }, + { value: 'mt', label: 'Malta' }, + { value: 'mh', label: 'Marshall Islands' }, + { value: 'mr', label: 'Mauritania' }, + { value: 'mu', label: 'Mauritius' }, + { value: 'mx', label: 'Mexico' }, + { value: 'fm', label: 'Micronesia' }, + { value: 'md', label: 'Moldova' }, + { value: 'mc', label: 'Monaco' }, + { value: 'mn', label: 'Mongolia' }, + { value: 'me', label: 'Montenegro' }, + { value: 'ma', label: 'Morocco' }, + { value: 'mz', label: 'Mozambique' }, + { value: 'mm', label: 'Myanmar' }, + { value: 'na', label: 'Namibia' }, + { value: 'nr', label: 'Nauru' }, + { value: 'np', label: 'Nepal' }, + { value: 'nl', label: 'Netherlands' }, + { value: 'nz', label: 'New Zealand' }, + { value: 'ni', label: 'Nicaragua' }, + { value: 'ne', label: 'Niger' }, + { value: 'ng', label: 'Nigeria' }, + { value: 'kp', label: 'North Korea' }, + { value: 'no', label: 'Norway' }, + { value: 'om', label: 'Oman' }, + { value: 'pk', label: 'Pakistan' }, + { value: 'pw', label: 'Palau' }, + { value: 'pa', label: 'Panama' }, + { value: 'pg', label: 'Papua New Guinea' }, + { value: 'py', label: 'Paraguay' }, + { value: 'pe', label: 'Peru' }, + { value: 'ph', label: 'Philippines' }, + { value: 'pl', label: 'Poland' }, + { value: 'pt', label: 'Portugal' }, + { value: 'qa', label: 'Qatar' }, + { value: 'ro', label: 'Romania' }, + { value: 'ru', label: 'Russia' }, + { value: 'rw', label: 'Rwanda' }, + { value: 'lc', label: 'Saint Lucia' }, + { value: 'vc', label: 'Saint Vincent and the Grenadines' }, + { value: 'ws', label: 'Samoa' }, + { value: 'sm', label: 'San Marino' }, + { value: 'st', label: 'Sao Tome and Principe' }, + { value: 'sa', label: 'Saudi Arabia' }, + { value: 'sn', label: 'Senegal' }, + { value: 'rs', label: 'Serbia' }, + { value: 'sc', label: 'Seychelles' }, + { value: 'sl', label: 'Sierra Leone' }, + { value: 'sg', label: 'Singapore' }, + { value: 'sk', label: 'Slovakia' }, + { value: 'si', label: 'Slovenia' }, + { value: 'sb', label: 'Solomon Islands' }, + { value: 'so', label: 'Somalia' }, + { value: 'za', label: 'South Africa' }, + { value: 'kr', label: 'South Korea' }, + { value: 'ss', label: 'South Sudan' }, + { value: 'es', label: 'Spain' }, + { value: 'lk', label: 'Sri Lanka' }, + { value: 'sd', label: 'Sudan' }, + { value: 'sr', label: 'Suriname' }, + { value: 'sz', label: 'Eswatini' }, + { value: 'se', label: 'Sweden' }, + { value: 'ch', label: 'Switzerland' }, + { value: 'sy', label: 'Syria' }, + { value: 'tw', label: 'Taiwan' }, + { value: 'tj', label: 'Tajikistan' }, + { value: 'tz', label: 'Tanzania' }, + { value: 'th', label: 'Thailand' }, + { value: 'tl', label: 'Timor-Leste' }, + { value: 'tg', label: 'Togo' }, + { value: 'to', label: 'Tonga' }, + { value: 'tt', label: 'Trinidad and Tobago' }, + { value: 'tn', label: 'Tunisia' }, + { value: 'tr', label: 'Turkey' }, + { value: 'tm', label: 'Turkmenistan' }, + { value: 'tv', label: 'Tuvalu' }, + { value: 'ug', label: 'Uganda' }, + { value: 'ua', label: 'Ukraine' }, + { value: 'ae', label: 'United Arab Emirates' }, + { value: 'gb', label: 'United Kingdom' }, + { value: 'us', label: 'United States' }, + { value: 'uy', label: 'Uruguay' }, + { value: 'uz', label: 'Uzbekistan' }, + { value: 'vu', label: 'Vanuatu' }, + { value: 'va', label: 'Vatican City' }, + { value: 've', label: 'Venezuela' }, + { value: 'vn', label: 'Vietnam' }, + { value: 'ye', label: 'Yemen' }, + { value: 'zm', label: 'Zambia' }, + { value: 'zw', label: 'Zimbabwe' }, +]; + +const educationGradeEnum = [ + { + value: 'NO_GRADE', + label: 'noGrade', + }, + { + value: 'PRE_KG', + label: 'preKg', + }, + { + value: 'KG', + label: 'kg', + }, + { + value: 'GRADE_1', + label: 'grade1', + }, + { + value: 'GRADE_2', + label: 'grade2', + }, + { + value: 'GRADE_3', + label: 'grade3', + }, + { + value: 'GRADE_4', + label: 'grade4', + }, + { + value: 'GRADE_5', + label: 'grade5', + }, + { + value: 'GRADE_6', + label: 'grade6', + }, + { + value: 'GRADE_7', + label: 'grade7', + }, + { + value: 'GRADE_8', + label: 'grade8', + }, + { + value: 'GRADE_9', + label: 'grade9', + }, + { + value: 'GRADE_10', + label: 'grade10', + }, + { + value: 'GRADE_11', + label: 'grade11', + }, + { + value: 'GRADE_12', + label: 'grade12', + }, + { + value: 'GRADUATE', + label: 'graduate', + }, +]; + +const maritalStatusEnum = [ + { + 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 genderEnum = [ + { + value: 'MALE', + label: 'male', + }, + { + value: 'FEMALE', + label: 'female', + }, + { + value: 'OTHER', + label: 'other', + }, +]; + +const employmentStatusEnum = [ + { + value: 'FULL_TIME', + label: 'fullTime', + }, + { + value: 'PART_TIME', + label: 'partTime', + }, + { + value: 'UNEMPLOYED', + label: 'unemployed', + }, +]; + +const userRoleEnum = [ + { + value: 'USER', + label: 'User', + }, + { + value: 'ADMIN', + label: 'Admin', + }, + { + value: 'SUPERADMIN', + label: 'Super Admin', + }, + { + value: 'NON_USER', + label: 'Non-User', + }, +]; + +export { + countryOptions, + educationGradeEnum, + maritalStatusEnum, + genderEnum, + employmentStatusEnum, + userRoleEnum, +}; diff --git a/src/utils/getOrganizationId.ts b/src/utils/getOrganizationId.ts new file mode 100644 index 0000000000..0a7c283e39 --- /dev/null +++ b/src/utils/getOrganizationId.ts @@ -0,0 +1,8 @@ +/* istanbul ignore next */ +const getOrganizationId = (url: string): string => { + const id = url?.split('=')[1]; + + return id?.split('#')[0]; +}; + +export default getOrganizationId; diff --git a/src/utils/getRefreshToken.test.ts b/src/utils/getRefreshToken.test.ts new file mode 100644 index 0000000000..58de898a66 --- /dev/null +++ b/src/utils/getRefreshToken.test.ts @@ -0,0 +1,54 @@ +// 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 new file mode 100644 index 0000000000..5d6f8aa2ce --- /dev/null +++ b/src/utils/getRefreshToken.ts @@ -0,0 +1,35 @@ +import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client'; +import { BACKEND_URL } from 'Constant/constant'; +import { REFRESH_TOKEN_MUTATION } from 'GraphQl/Mutations/mutations'; +import useLocalStorage from './useLocalstorage'; + +export async function refreshToken(): Promise { + const client = new ApolloClient({ + link: new HttpLink({ + uri: BACKEND_URL, + }), + cache: new InMemoryCache(), + }); + + const { getItem, setItem } = useLocalStorage(); + + const refreshToken = getItem('refreshToken'); + /* istanbul ignore next */ + try { + const { data } = await client.mutate({ + mutation: REFRESH_TOKEN_MUTATION, + variables: { + refreshToken: refreshToken, + }, + }); + + setItem('token', data.refreshToken.accessToken); + setItem('refreshToken', data.refreshToken.refreshToken); + + window.location.reload(); + return true; + } catch (error) { + console.error('Failed to refresh token', error); + return false; + } +} diff --git a/src/utils/i18n.ts b/src/utils/i18n.ts new file mode 100644 index 0000000000..3aafbd843d --- /dev/null +++ b/src/utils/i18n.ts @@ -0,0 +1,27 @@ +import i18n from 'i18next'; +import { initReactI18next } from 'react-i18next'; +import LanguageDetector from 'i18next-browser-languagedetector'; +import HttpApi from 'i18next-http-backend'; + +import { languageArray } from './languages'; + +i18n + .use(initReactI18next) + .use(LanguageDetector) + .use(HttpApi) + .init({ + ns: ['translation', 'errors', 'common'], + defaultNS: 'translation', + fallbackLng: 'en', + supportedLngs: languageArray, + detection: { + order: ['cookie', 'htmlTag', 'localStorage', 'path', 'subdomain'], + caches: ['cookie'], + }, + backend: { + loadPath: '/locales/{{lng}}/{{ns}}.json', + }, + // debug: true, + }); + +export default i18n; diff --git a/src/utils/i18nForTest.ts b/src/utils/i18nForTest.ts new file mode 100644 index 0000000000..673b4b0750 --- /dev/null +++ b/src/utils/i18nForTest.ts @@ -0,0 +1,34 @@ +import i18n from 'i18next'; +import { initReactI18next } from 'react-i18next'; +import LanguageDetector from 'i18next-browser-languagedetector'; +import HttpApi from 'i18next-http-backend'; + +import { languageArray } from './languages'; +import translationEnglish from '../../public/locales/en/translation.json'; +import translationCommonEnglish from '../../public/locales/en/common.json'; +import translationErrorEnglish from '../../public/locales/en/errors.json'; + +i18n + .use(LanguageDetector) + .use(HttpApi) + .use(initReactI18next) + .init({ + ns: ['translation', 'errors', 'common'], + defaultNS: 'translation', + fallbackLng: 'en', + supportedLngs: languageArray, + detection: { + order: ['cookie', 'htmlTag', 'localStorage', 'path', 'subdomain'], + caches: ['cookie'], + }, + resources: { + en: { + translation: translationEnglish, + common: translationCommonEnglish, + errors: translationErrorEnglish, + }, + }, + react: { useSuspense: false }, + }); + +export default i18n; diff --git a/src/utils/interfaces.ts b/src/utils/interfaces.ts new file mode 100644 index 0000000000..c4e15d0718 --- /dev/null +++ b/src/utils/interfaces.ts @@ -0,0 +1,499 @@ +export interface InterfaceUserType { + user: { + firstName: string; + lastName: string; + image: string | null; + email: string; + }; +} + +export interface InterfaceActionItemCategoryInfo { + _id: string; + name: string; + isDisabled: boolean; +} + +export interface InterfaceActionItemCategoryList { + actionItemCategoriesByOrganization: InterfaceActionItemCategoryInfo[]; +} + +export interface InterfaceActionItemInfo { + _id: string; + assignee: { + _id: string; + firstName: string; + lastName: string; + }; + assigner: { + _id: string; + firstName: string; + lastName: string; + }; + actionItemCategory: { + _id: string; + name: string; + }; + preCompletionNotes: string; + postCompletionNotes: string; + assignmentDate: Date; + dueDate: Date; + completionDate: Date; + isCompleted: boolean; + event: { + _id: string; + title: string; + }; + creator: { + _id: string; + firstName: string; + lastName: string; + }; +} + +export interface InterfaceActionItemList { + actionItemsByOrganization: InterfaceActionItemInfo[]; +} + +export interface InterfaceMembersList { + organizations: { + _id: string; + members: InterfaceMemberInfo[]; + }[]; +} + +export interface InterfaceMemberInfo { + _id: string; + firstName: string; + lastName: string; + email: string; + image: string; + createdAt: string; + organizationsBlockedBy: { + _id: string; + }[]; +} + +export interface InterfaceOrgConnectionInfoType { + _id: string; + image: string | null; + creator: { + _id: string; + firstName: string; + lastName: string; + }; + name: string; + members: { + _id: string; + }[]; + admins: { + _id: string; + }[]; + createdAt: string; + address: InterfaceAddress; +} +export interface InterfaceOrgConnectionType { + organizationsConnection: InterfaceOrgConnectionInfoType[]; +} + +export interface InterfaceQueryOrganizationsListObject { + _id: string; + image: string | null; + creator: { + firstName: string; + lastName: string; + email: string; + }; + name: string; + description: string; + address: InterfaceAddress; + userRegistrationRequired: boolean; + visibleInSearch: boolean; + members: { + _id: string; + firstName: string; + lastName: string; + email: string; + }[]; + admins: { + _id: string; + firstName: string; + lastName: string; + email: string; + createdAt: string; + }[]; + membershipRequests: { + _id: string; + user: { + firstName: string; + lastName: string; + email: string; + }; + }[]; + blockedUsers: { + _id: string; + firstName: string; + lastName: string; + email: string; + }[]; +} + +export interface InterfaceQueryOrganizationListObject { + _id: string; + image: string | null; + creator: { + firstName: string; + lastName: string; + }; + name: string; + members: { + _id: string; + }[]; + admins: { + _id: string; + }[]; + createdAt: string; + address: InterfaceAddress; +} + +export interface InterfacePostForm { + posttitle: string; + postinfo: string; + postphoto: string | null; + postvideo: string | null; + pinned: boolean; +} +export interface InterfaceQueryOrganizationPostListItem { + posts: { + edges: { + node: { + _id: string; + title: string; + text: string; + imageUrl: string | null; + videoUrl: string | null; + creator: { + _id: string; + firstName: string; + lastName: string; + email: string; + }; + createdAt: string; + likeCount: number; + commentCount: number; + pinned: boolean; + + likedBy: { _id: string }[]; + comments: { + _id: string; + text: string; + creator: { _id: string }; + createdAt: string; + likeCount: number; + likedBy: { _id: string }[]; + }[]; + }; + cursor: string; + }[]; + pageInfo: { + startCursor: string; + endCursor: string; + hasNextPage: boolean; + hasPreviousPage: boolean; + }; + totalCount: number; + }; +} + +export interface InterfaceQueryOrganizationAdvertisementListItem { + advertisements: { + edges: { + node: { + _id: string; + name: string; + mediaUrl: string; + endDate: string; + startDate: string; + type: 'BANNER' | 'MENU' | 'POPUP'; + }; + cursor: string; + }[]; + pageInfo: { + startCursor: string; + endCursor: string; + hasNextPage: boolean; + hasPreviousPage: boolean; + }; + totalCount: number; + }; +} + +export interface InterfaceQueryOrganizationFundCampaigns { + campaigns: { + _id: string; + name: string; + fundingGoal: number; + startDate: Date; + endDate: Date; + createdAt: string; + currency: string; + }[]; +} +export interface InterfaceQueryFundCampaignsPledges { + name: string; + fundingGoal: number; + currency: string; + startDate: Date; + endDate: Date; + pledges: { + _id: string; + amount: number; + currency: string; + endDate: string; + startDate: string; + users: InterfacePledger[]; + }[]; +} +export interface InterfaceFundInfo { + _id: string; + name: string; + refrenceNumber: string; + taxDeductible: boolean; + isArchived: boolean; + isDefault: boolean; + createdAt: string; + organizationId: string; + creator: { _id: string; firstName: string; lastName: string }; +} +export interface InterfaceCampaignInfo { + _id: string; + name: string; + fundingGoal: number; + startDate: Date; + endDate: Date; + createdAt: string; + currency: string; +} +export interface InterfacePledgeInfo { + _id: string; + amount: number; + currency: string; + endDate: string; + startDate: string; + users: InterfacePledger[]; +} +export interface InterfaceQueryOrganizationEventListItem { + _id: string; + title: string; + description: string; + startDate: string; + endDate: string; + location: string; + startTime: string; + endTime: string; + allDay: boolean; + recurring: boolean; + isPublic: boolean; + isRegisterable: boolean; +} + +export interface InterfaceQueryBlockPageMemberListItem { + _id: string; + firstName: string; + lastName: string; + email: string; + organizationsBlockedBy: { + _id: string; + }[]; +} + +export interface InterfaceQueryUserListItem { + user: { + _id: string; + firstName: string; + lastName: string; + image: string | null; + email: string; + organizationsBlockedBy: { + _id: string; + name: string; + image: string | null; + address: InterfaceAddress; + creator: { + _id: string; + firstName: string; + lastName: string; + email: string; + image: string | null; + }; + createdAt: string; + }[]; + joinedOrganizations: { + _id: string; + name: string; + address: InterfaceAddress; + image: string | null; + createdAt: string; + creator: { + _id: string; + firstName: string; + lastName: string; + email: string; + image: string | null; + }; + }[]; + createdAt: string; + registeredEvents: { _id: string }[]; + membershipRequests: { _id: string }[]; + }; + appUserProfile: { + _id: string; + adminFor: { _id: string }[]; + isSuperAdmin: boolean; + createdOrganizations: { _id: string }[]; + createdEvents: { _id: string }[]; + eventAdmin: { _id: string }[]; + }; +} + +export interface InterfaceQueryVenueListItem { + _id: string; + name: string; + description: string | null; + image: string | null; + capacity: string; +} + +export interface InterfaceAddress { + city: string; + countryCode: string; + dependentLocality: string; + line1: string; + line2: string; + postalCode: string; + sortingCode: string; + state: string; +} +export interface InterfaceCreateFund { + fundName: string; + fundRef: string; + isDefault: boolean; + isArchived: boolean; + taxDeductible: boolean; +} + +export interface InterfacePostCard { + id: string; + creator: { + firstName: string; + lastName: string; + email: string; + id: string; + }; + postedAt: string; + image: string | null; + video: string | null; + text: string; + title: string; + likeCount: number; + commentCount: number; + comments: { + id: string; + creator: { + id: string; + firstName: string; + lastName: string; + email: string; + }; + likeCount: number; + likedBy: { + id: string; + }[]; + text: string; + }[]; + likedBy: { + firstName: string; + lastName: string; + id: string; + }[]; + fetchPosts: () => void; +} + +export interface InterfaceCreatePledge { + pledgeUsers: InterfacePledger[]; + pledgeAmount: number; + pledgeCurrency: string; + pledgeStartDate: Date; + pledgeEndDate: Date; +} + +export interface InterfaceQueryMembershipRequestsListItem { + organizations: { + _id: string; + membershipRequests: { + _id: string; + user: { + _id: string; + firstName: string; + lastName: string; + email: string; + }; + }[]; + }[]; +} + +export interface InterfacePledger { + _id: string; + firstName: string; + lastName: string; + image: string | null; +} +export interface InterfaceAgendaItemCategoryInfo { + _id: string; + name: string; + description: string; + createdBy: { + _id: string; + firstName: string; + lastName: string; + }; +} + +export interface InterfaceAgendaItemCategoryList { + agendaItemCategoriesByOrganization: InterfaceAgendaItemCategoryInfo[]; +} + +export interface InterfaceAgendaItemInfo { + _id: string; + title: string; + description: string; + duration: string; + attachments: string[]; + createdBy: { + _id: string; + firstName: string; + lastName: string; + }; + urls: string[]; + users: { + _id: string; + firstName: string; + lastName: string; + }[]; + sequence: number; + categories: { + _id: string; + name: string; + }[]; + organization: { + _id: string; + name: string; + }; + relatedEvent: { + _id: string; + title: string; + }; +} + +export interface InterfaceAgendaItemList { + agendaItemByEvent: InterfaceAgendaItemInfo[]; +} diff --git a/src/utils/languages.ts b/src/utils/languages.ts new file mode 100644 index 0000000000..9e8e019784 --- /dev/null +++ b/src/utils/languages.ts @@ -0,0 +1,31 @@ +const languageArray = ['en', 'fr', 'hi', 'sp', 'zh']; + +const languages = [ + { + code: 'en', + name: 'English', // english + country_code: 'gb', + }, + { + code: 'fr', + name: 'Français', // french + country_code: 'fr', + }, + { + code: 'hi', + name: 'हिन्दी', // hindi + country_code: 'in', + }, + { + code: 'sp', + name: 'Español', // spanish + country_code: 'ar', + }, + { + code: 'zh', + name: '中國人', // chinese (traditional) + country_code: 'cn', + }, +]; + +export { languageArray, languages }; diff --git a/src/utils/linkValid.test.tsx b/src/utils/linkValid.test.tsx new file mode 100644 index 0000000000..0cf8a9785b --- /dev/null +++ b/src/utils/linkValid.test.tsx @@ -0,0 +1,15 @@ +import { isValidLink } from './linkValidator'; + +describe('Testing link validator', () => { + it('returns true for a valid link', () => { + const validLink = 'https://www.example.com'; + const result = isValidLink(validLink); + expect(result).toBe(true); + }); + + it('returns false for an invalid link', () => { + const invalidLink = 'not a valid link'; + const result = isValidLink(invalidLink); + expect(result).toBe(false); + }); +}); diff --git a/src/utils/linkValidator.ts b/src/utils/linkValidator.ts new file mode 100644 index 0000000000..fac4766a3b --- /dev/null +++ b/src/utils/linkValidator.ts @@ -0,0 +1,8 @@ +export const isValidLink = (link: string): boolean => { + try { + new URL(link); + return true; + } catch (error) { + return false; + } +}; diff --git a/src/utils/recurrenceUtils/index.ts b/src/utils/recurrenceUtils/index.ts new file mode 100644 index 0000000000..9b376fc83d --- /dev/null +++ b/src/utils/recurrenceUtils/index.ts @@ -0,0 +1,3 @@ +export * from './recurrenceTypes'; +export * from './recurrenceConstants'; +export * from './recurrenceUtilityFunctions'; diff --git a/src/utils/recurrenceUtils/recurrenceConstants.ts b/src/utils/recurrenceUtils/recurrenceConstants.ts new file mode 100644 index 0000000000..0b2dd68b4f --- /dev/null +++ b/src/utils/recurrenceUtils/recurrenceConstants.ts @@ -0,0 +1,87 @@ +/* + Recurrence constants +*/ + +import { + Frequency, + RecurrenceEndOption, + RecurringEventMutationType, + WeekDays, +} from './recurrenceTypes'; + +// recurrence frequency mapping +export const frequencies = { + [Frequency.DAILY]: 'Day', + [Frequency.WEEKLY]: 'Week', + [Frequency.MONTHLY]: 'Month', + [Frequency.YEARLY]: 'Year', +}; + +// recurrence days options to select from in the UI +export const daysOptions = ['S', 'M', 'T', 'W', 'T', 'F', 'S']; + +// recurrence days array +export const Days = [ + WeekDays.SUNDAY, + WeekDays.MONDAY, + WeekDays.TUESDAY, + WeekDays.WEDNESDAY, + WeekDays.THURSDAY, + WeekDays.FRIDAY, + WeekDays.SATURDAY, +]; + +// constants for recurrence end options +export const endsNever = RecurrenceEndOption.never; +export const endsOn = RecurrenceEndOption.on; +export const endsAfter = RecurrenceEndOption.after; + +// recurrence end options array +export const recurrenceEndOptions = [endsNever, endsOn, endsAfter]; + +// different types of updations / deletions on recurring events +export const thisInstance = RecurringEventMutationType.thisInstance; +export const thisAndFollowingInstances = + RecurringEventMutationType.thisAndFollowingInstances; +export const allInstances = RecurringEventMutationType.allInstances; + +export const recurringEventMutationOptions = [ + thisInstance, + thisAndFollowingInstances, + allInstances, +]; + +// array of week days containing 'MO' to 'FR +export const mondayToFriday = Days.filter( + (day) => day !== WeekDays.SATURDAY && day !== WeekDays.SUNDAY, +); + +// names of week days +export const dayNames = { + [WeekDays.SUNDAY]: 'Sunday', + [WeekDays.MONDAY]: 'Monday', + [WeekDays.TUESDAY]: 'Tuesday', + [WeekDays.WEDNESDAY]: 'Wednesday', + [WeekDays.THURSDAY]: 'Thursday', + [WeekDays.FRIDAY]: 'Friday', + [WeekDays.SATURDAY]: 'Saturday', +}; + +// names of months +export const monthNames = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', +]; + +// week day's occurences in month +export const weekDayOccurences = ['First', 'Second', 'Third', 'Fourth', 'Last']; diff --git a/src/utils/recurrenceUtils/recurrenceTypes.ts b/src/utils/recurrenceUtils/recurrenceTypes.ts new file mode 100644 index 0000000000..684c98ad87 --- /dev/null +++ b/src/utils/recurrenceUtils/recurrenceTypes.ts @@ -0,0 +1,59 @@ +/* + Recurrence types +*/ + +// interface for the recurrenceRuleStateData that would be sent to the backend +export interface InterfaceRecurrenceRuleState { + recurrenceStartDate: Date; + recurrenceEndDate: Date | null; + frequency: Frequency; + weekDays: WeekDays[]; + interval: number; + count: number | undefined; + weekDayOccurenceInMonth: number | undefined; +} + +// interface for the RecurrenceRule document that would be fetched from the backend +export interface InterfaceRecurrenceRule { + recurrenceStartDate: string; + recurrenceEndDate: string | null; + frequency: Frequency; + weekDays: WeekDays[]; + interval: number; + count: number | null; + weekDayOccurenceInMonth: number | null; +} + +// recurrence frequency +export enum Frequency { + DAILY = 'DAILY', + WEEKLY = 'WEEKLY', + MONTHLY = 'MONTHLY', + YEARLY = 'YEARLY', +} + +// recurrence week days +export enum WeekDays { + SUNDAY = 'SUNDAY', + MONDAY = 'MONDAY', + TUESDAY = 'TUESDAY', + WEDNESDAY = 'WEDNESDAY', + THURSDAY = 'THURSDAY', + FRIDAY = 'FRIDAY', + SATURDAY = 'SATURDAY', +} + +// recurrence end options +// i.e. whether it 'never' ends, ends 'on' a certain date, or 'after' a certain number of occurences +export enum RecurrenceEndOption { + never = 'never', + on = 'on', + after = 'after', +} + +// update / delete options of recurring events +export enum RecurringEventMutationType { + thisInstance = 'thisInstance', + thisAndFollowingInstances = 'thisAndFollowingInstances', + allInstances = 'allInstances', +} diff --git a/src/utils/recurrenceUtils/recurrenceUtilityFunctions.ts b/src/utils/recurrenceUtils/recurrenceUtilityFunctions.ts new file mode 100644 index 0000000000..d316174042 --- /dev/null +++ b/src/utils/recurrenceUtils/recurrenceUtilityFunctions.ts @@ -0,0 +1,252 @@ +/* + Recurrence utility functions +*/ + +import dayjs from 'dayjs'; +import { + Days, + dayNames, + mondayToFriday, + monthNames, + weekDayOccurences, +} from './recurrenceConstants'; +import { Frequency } from './recurrenceTypes'; +import type { + WeekDays, + InterfaceRecurrenceRuleState, + InterfaceRecurrenceRule, +} from './recurrenceTypes'; + +// function that generates the recurrence rule text to display +// e.g. - 'Weekly on Sunday, until Feburary 23, 2029' +export const getRecurrenceRuleText = ( + recurrenceRuleState: InterfaceRecurrenceRuleState, +): string => { + let recurrenceRuleText = ''; + const { + recurrenceStartDate, + recurrenceEndDate, + frequency, + weekDays, + interval, + count, + weekDayOccurenceInMonth, + } = recurrenceRuleState; + + switch (frequency) { + case Frequency.DAILY: + if (interval && interval > 1) { + recurrenceRuleText = `Every ${interval} days`; + } else { + recurrenceRuleText = 'Daily'; + } + break; + + case Frequency.WEEKLY: + if (isMondayToFriday(weekDays)) { + if (interval && interval > 1) { + recurrenceRuleText = `Every ${interval} weeks, `; + } + recurrenceRuleText += 'Monday to Friday'; + break; + } + if (interval && interval > 1) { + recurrenceRuleText = `Every ${interval} weeks on `; + } else { + recurrenceRuleText = 'Weekly on '; + } + recurrenceRuleText += getWeekDaysString(weekDays); + break; + + case Frequency.MONTHLY: + if (interval && interval > 1) { + recurrenceRuleText = `Every ${interval} months on `; + } else { + recurrenceRuleText = 'Monthly on '; + } + + if (weekDayOccurenceInMonth) { + const getOccurence = + weekDayOccurenceInMonth !== -1 ? weekDayOccurenceInMonth - 1 : 4; + recurrenceRuleText += `${weekDayOccurences[getOccurence]} ${dayNames[Days[recurrenceStartDate.getDay()]]}`; + } else { + recurrenceRuleText += `Day ${recurrenceStartDate.getDate()}`; + } + break; + + case Frequency.YEARLY: + if (interval && interval > 1) { + recurrenceRuleText = `Every ${interval} years on `; + } else { + recurrenceRuleText = 'Annually on '; + } + recurrenceRuleText += `${monthNames[recurrenceStartDate.getMonth()]} ${recurrenceStartDate.getDate()}`; + break; + } + + if (recurrenceEndDate) { + const options = { year: 'numeric', month: 'long', day: 'numeric' }; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + recurrenceRuleText += `, until ${recurrenceEndDate.toLocaleDateString('en-US', options)}`; + } + + if (count) { + recurrenceRuleText += `, ${count} ${count > 1 ? 'times' : 'time'}`; + } + + return recurrenceRuleText; +}; + +// function that generates a string of selected week days for the recurrence rule text +// e.g. - for an array ['MONDAY', 'TUESDAY', 'FRIDAY'], it would output: 'Monday, Tuesday & Friday' +const getWeekDaysString = (weekDays: WeekDays[]): string => { + const fullDayNames = weekDays.map((day) => dayNames[day]); + + let weekDaysString = fullDayNames.join(', '); + + const lastCommaIndex = weekDaysString.lastIndexOf(','); + if (lastCommaIndex !== -1) { + weekDaysString = + weekDaysString.substring(0, lastCommaIndex) + + ' &' + + weekDaysString.substring(lastCommaIndex + 1); + } + + return weekDaysString; +}; + +// function that checks if the array contains all days from Monday to Friday +const isMondayToFriday = (weekDays: WeekDays[]): boolean => { + return mondayToFriday.every((day) => weekDays.includes(day)); +}; + +// function that returns the occurence of the weekday in a month, +// i.e. First Monday, Second Monday, Last Monday, etc. +export const getWeekDayOccurenceInMonth = (date: Date): number => { + const dayOfMonth = date.getDate(); + + // Calculate the current occurrence + const occurrence = Math.ceil(dayOfMonth / 7); + + return occurrence; +}; + +// function that checks whether it's the last occurence of the weekday in that month +export const isLastOccurenceOfWeekDay = (date: Date): boolean => { + const currentDay = date.getDay(); + + const lastOccurenceInMonth = new Date( + date.getFullYear(), + date.getMonth() + 1, + 0, + ); + + // set the lastOccurenceInMonth to that day's last occurence + while (lastOccurenceInMonth.getDay() !== currentDay) { + lastOccurenceInMonth.setDate(lastOccurenceInMonth.getDate() - 1); + } + + return date.getDate() === lastOccurenceInMonth.getDate(); +}; + +// function that evaluates whether the startDate or endDate of a recurring event instance have changed +export const haveInstanceDatesChanged = ( + instanceOriginalStartDate: string, + instanceOriginalEndDate: string, + instanceNewStartDate: string, + instanceNewEndDate: string, +): boolean => { + return ( + instanceOriginalStartDate !== instanceNewStartDate || + instanceOriginalEndDate !== instanceNewEndDate + ); +}; + +// function that checks whether the recurrence rule has changed +export const hasRecurrenceRuleChanged = ( + originalRecurrencerule: InterfaceRecurrenceRule | null, + recurrenceRuleState: InterfaceRecurrenceRuleState, +): boolean => { + if (!originalRecurrencerule) { + return false; + } + + const newRecurrenceRule = getRecurrenceRule(recurrenceRuleState); + + const recurrenceProperties = Object.keys( + newRecurrenceRule, + ) as (keyof InterfaceRecurrenceRule)[]; + + for (const recurrenceProperty of recurrenceProperties) { + if (recurrenceProperty === 'weekDays') { + if ( + weekDaysHaveChanged( + originalRecurrencerule.weekDays, + newRecurrenceRule.weekDays, + ) + ) { + return true; + } + } else if ( + originalRecurrencerule[recurrenceProperty] !== + newRecurrenceRule[recurrenceProperty] + ) { + return true; + } + } + + return false; +}; + +// function that returns the recurrence rule object based on the current recurrence rule state +const getRecurrenceRule = ( + recurrenceRuleState: InterfaceRecurrenceRuleState, +): InterfaceRecurrenceRule => { + const { + recurrenceStartDate, + recurrenceEndDate, + frequency, + weekDays, + interval, + count, + weekDayOccurenceInMonth, + } = recurrenceRuleState; + + const originalRecurrencerule = { + recurrenceStartDate: dayjs(recurrenceStartDate).format('YYYY-MM-DD'), + recurrenceEndDate: recurrenceEndDate + ? dayjs(recurrenceEndDate).format('YYYY-MM-DD') + : null, + frequency, + weekDays: weekDays?.length ? weekDays : [], + interval, + count: count ?? null, + weekDayOccurenceInMonth: weekDayOccurenceInMonth ?? null, + }; + + return originalRecurrencerule; +}; + +// function to check whether recurrence weekDays have been changed +const weekDaysHaveChanged = ( + originalWeekDays: WeekDays[], + currentWeekDays: WeekDays[], +): boolean => { + if (originalWeekDays.length !== currentWeekDays.length) { + return true; + } + + // Sort both arrays + const sortedOriginalWeekDays = [...originalWeekDays].sort(); + const sortedCurrentWeekDays = [...currentWeekDays].sort(); + + // Compare arrays + for (let i = 0; i < sortedOriginalWeekDays.length; i++) { + if (sortedOriginalWeekDays[i] !== sortedCurrentWeekDays[i]) { + return true; + } + } + + return false; +}; diff --git a/src/utils/useLocalstorage.test.ts b/src/utils/useLocalstorage.test.ts new file mode 100644 index 0000000000..7483da4da2 --- /dev/null +++ b/src/utils/useLocalstorage.test.ts @@ -0,0 +1,137 @@ +import { + getStorageKey, + getItem, + setItem, + removeItem, + useLocalStorage, +} from './useLocalstorage'; + +describe('Storage Helper Functions', () => { + beforeEach(() => { + localStorage.clear(); + }); + + it('generates correct storage key', () => { + const key = 'testKey'; + const prefix = 'TestPrefix'; + const storageKey = getStorageKey(prefix, key); + expect(storageKey).toBe('TestPrefix_testKey'); + }); + + it('gets item from local storage', () => { + const key = 'testKey'; + const prefix = 'TestPrefix'; + const value = 'data'; + localStorage.setItem('TestPrefix_testKey', JSON.stringify(value)); + + const retrievedValue = getItem(prefix, key); + + expect(retrievedValue).toEqual(value); + }); + + it('returns null when getting a non-existent item', () => { + const key = 'nonExistentKey'; + const prefix = 'TestPrefix'; + + const retrievedValue = getItem(prefix, key); + + expect(retrievedValue).toBeNull(); + }); + + it('sets item in local storage', () => { + const key = 'testKey'; + const prefix = 'TestPrefix'; + const value = { some: 'data' }; + + setItem(prefix, key, value); + + const storedData = localStorage.getItem('TestPrefix_testKey'); + const parsedData = storedData ? JSON.parse(storedData) : null; + + expect(parsedData).toEqual(value); + }); + + it('removes item from local storage', () => { + const key = 'testKey'; + const prefix = 'TestPrefix'; + const value = 'data'; + localStorage.setItem('TestPrefix_testKey', value); + + removeItem(prefix, key); + + const retrievedValue = localStorage.getItem('TestPrefix_testKey'); + expect(retrievedValue).toBeNull(); + }); + + it('uses default prefix for useLocalStorage', () => { + const storageHelper = useLocalStorage(); + const key = 'testKey'; + const value = { some: 'data' }; + + storageHelper.setItem(key, value); + + const storedData = localStorage.getItem('Talawa-admin_testKey'); + const parsedData = storedData ? JSON.parse(storedData) : null; + + expect(parsedData).toEqual(value); + }); + + it('uses provided prefix for useLocalStorage', () => { + const customPrefix = 'CustomPrefix'; + const storageHelper = useLocalStorage(customPrefix); + const key = 'testKey'; + const value = { some: 'data' }; + + storageHelper.setItem(key, value); + + const storedData = localStorage.getItem('CustomPrefix_testKey'); + const parsedData = storedData ? JSON.parse(storedData) : null; + + expect(parsedData).toEqual(value); + }); + + it('calls getStorageKey with the correct parameters', () => { + const customPrefix = 'CustomPrefix'; + const storageHelper = useLocalStorage(customPrefix); + const key = 'testKey'; + + const spyGetStorageKey = jest.spyOn(storageHelper, 'getStorageKey'); + storageHelper.getStorageKey(key); + + expect(spyGetStorageKey).toHaveBeenCalledWith(key); + }); + + it('calls getItem with the correct parameters', () => { + const customPrefix = 'CustomPrefix'; + const storageHelper = useLocalStorage(customPrefix); + const key = 'testKey'; + + const spyGetItem = jest.spyOn(storageHelper, 'getItem'); + storageHelper.getItem(key); + + expect(spyGetItem).toHaveBeenCalledWith(key); + }); + + it('calls setItem with the correct parameters', () => { + const customPrefix = 'CustomPrefix'; + const storageHelper = useLocalStorage(customPrefix); + const key = 'testKey'; + const value = 'data'; + + const spySetItem = jest.spyOn(storageHelper, 'setItem'); + storageHelper.setItem(key, value); + + expect(spySetItem).toHaveBeenCalledWith(key, value); + }); + + it('calls removeItem with the correct parameters', () => { + const customPrefix = 'CustomPrefix'; + const storageHelper = useLocalStorage(customPrefix); + const key = 'testKey'; + + const spyRemoveItem = jest.spyOn(storageHelper, 'removeItem'); + storageHelper.removeItem(key); + + expect(spyRemoveItem).toHaveBeenCalledWith(key); + }); +}); diff --git a/src/utils/useLocalstorage.ts b/src/utils/useLocalstorage.ts new file mode 100644 index 0000000000..9650381085 --- /dev/null +++ b/src/utils/useLocalstorage.ts @@ -0,0 +1,72 @@ +/** + * Helper interface for managing localStorage operations. + */ +interface InterfaceStorageHelper { + getItem: (key: string) => any; + setItem: (key: string, value: any) => void; + removeItem: (key: string) => void; + getStorageKey: (key: string) => string; +} + +const PREFIX = 'Talawa-admin'; + +/** + * Generates the prefixed key for storage. + * @param prefix - Prefix to be added to the key, common for all keys. + * @param key - The unique name identifying the value. + * @returns - Prefixed key. + */ +export const getStorageKey = (prefix: string, key: string): string => { + return `${prefix}_${key}`; +}; + +/** + * Retrieves the stored value for the given key from local storage. + * @param prefix - Prefix to be added to the key, common for all keys. + * @param key - The unique name identifying the value. + * @returns - The stored value for the given key from local storage. + */ +export const getItem = (prefix: string, key: string): any => { + const prefixedKey = getStorageKey(prefix, key); + const storedData = localStorage.getItem(prefixedKey); + return storedData ? JSON.parse(storedData) : null; +}; + +/** + * Sets the value for the given key in local storage. + * @param prefix - Prefix to be added to the key, common for all keys. + * @param key - The unique name identifying the value. + * @param value - The value for the key. + */ +export const setItem = (prefix: string, key: string, value: any): void => { + const prefixedKey = getStorageKey(prefix, key); + localStorage.setItem(prefixedKey, JSON.stringify(value)); +}; + +/** + * Removes the value associated with the given key from local storage. + * @param prefix - Prefix to be added to the key, common for all keys. + * @param key - The unique name identifying the value. + */ +export const removeItem = (prefix: string, key: string): void => { + const prefixedKey = getStorageKey(prefix, key); + localStorage.removeItem(prefixedKey); +}; + +/** + * Custom hook for simplified localStorage operations. + * @param prefix - Prefix to be added to the key, common for all keys. Default is 'Talawa-admin'. + * @returns - Functions to getItem, setItem, removeItem, and getStorageKey. + */ +export const useLocalStorage = ( + prefix: string = PREFIX, +): InterfaceStorageHelper => { + return { + getItem: (key: string) => getItem(prefix, key), + setItem: (key: string, value: any) => setItem(prefix, key, value), + removeItem: (key: string) => removeItem(prefix, key), + getStorageKey: (key: string) => getStorageKey(prefix, key), + }; +}; + +export default useLocalStorage; diff --git a/talawa-admin-docs/.nojekyll b/talawa-admin-docs/.nojekyll new file mode 100644 index 0000000000..e2ac6616ad --- /dev/null +++ b/talawa-admin-docs/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/talawa-admin-docs/Dockerfile b/talawa-admin-docs/Dockerfile new file mode 100644 index 0000000000..e69de29bb2 diff --git a/talawa-admin-docs/README.md b/talawa-admin-docs/README.md new file mode 100644 index 0000000000..82dc89754c --- /dev/null +++ b/talawa-admin-docs/README.md @@ -0,0 +1,52 @@ +talawa-admin / [Modules](modules.md) + +# Talawa Admin +💬 Join the community on Slack. The link can be found in the `Talawa` [README.md](https://github.com/PalisadoesFoundation/talawa) file. + +![talawa-logo-lite-200x200](https://github.com/PalisadoesFoundation/talawa-admin/assets/16875803/26291ec5-d3c1-4135-8bc7-80885dff613d) + +[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) +[![GitHub stars](https://img.shields.io/github/stars/PalisadoesFoundation/talawa-admin.svg?style=social&label=Star&maxAge=2592000)](https://github.com/PalisadoesFoundation/talawa-admin) +[![GitHub forks](https://img.shields.io/github/forks/PalisadoesFoundation/talawa-admin.svg?style=social&label=Fork&maxAge=2592000)](https://github.com/PalisadoesFoundation/talawa-admin) +[![codecov](https://codecov.io/gh/PalisadoesFoundation/talawa-admin/branch/develop/graph/badge.svg?token=II0R0RREES)](https://codecov.io/gh/PalisadoesFoundation/talawa-admin) + +Talawa is a modular open source project to manage group activities of both non-profit organizations and businesses. + +Core features include: + +1. Membership management +2. Groups management +3. Event registrations +4. Recurring meetings +5. Facilities registrations + +`talawa` is based on the original `quito` code created by the [Palisadoes Foundation][pfd] as part of its annual Calico Challenge program. Calico provides paid summer internships for Jamaican university students to work on selected open source projects. They are mentored by software professionals and receive stipends based on the completion of predefined milestones. Calico was started in 2015. Visit [The Palisadoes Foundation's website](http://www.palisadoes.org/) for more details on its origin and activities. + +# Table of Contents + +\