From 4970031cdbecf8d7987bef9c1d088b9bf43ccff8 Mon Sep 17 00:00:00 2001 From: Iveta Date: Mon, 14 Aug 2023 15:44:13 -0700 Subject: [PATCH] Initial commit for open source release Co-authored-by: Charles Shin --- .dockerignore | 3 + .eslintignore | 13 + .eslintrc.json | 51 + .../workflows/docker_image_public_release.yml | 97 + .github/workflows/test-build.yml | 28 + .gitignore | 30 + .husky/.gitignore | 1 + .husky/post-merge | 4 + .husky/pre-commit | 4 + .prettierignore | 4 + .prettierrc.json | 12 + CHANGELOG.md | 25 + Dockerfile | 24 + LICENSE | 202 + Makefile | 15 + README.md | 34 + babel.config.js | 22 + nginx.conf | 23 + package.json | 119 + public/favicon.ico | Bin 0 -> 7406 bytes public/logo192.png | Bin 0 -> 3843 bytes public/logo512.png | Bin 0 -> 11240 bytes public/manifest.json | 25 + public/resources/disbursement-template.csv | 1 + public/robots.txt | 3 + src/App.tsx | 289 + src/api/authLogin.ts | 29 + src/api/authRefreshToken.ts | 19 + src/api/deleteAsset.ts | 18 + src/api/getAssets.ts | 15 + src/api/getCountries.ts | 15 + src/api/getDisbursementDetails.ts | 18 + src/api/getDisbursementDrafts.ts | 21 + src/api/getDisbursementInstructions.ts | 22 + src/api/getDisbursementReceivers.ts | 25 + src/api/getDisbursements.ts | 29 + src/api/getOrgInfo.ts | 15 + src/api/getOrgLogo.ts | 8 + src/api/getPaymentDetails.ts | 18 + src/api/getPayments.ts | 26 + src/api/getProfileInfo.ts | 17 + src/api/getReceiverDetails.ts | 18 + src/api/getReceivers.ts | 26 + src/api/getStatistics.ts | 15 + src/api/getStellarAccountInfo.ts | 17 + src/api/getStellarAccountPayments.ts | 32 + src/api/getStellarTransaction.ts | 20 + src/api/getUsers.ts | 15 + src/api/getWallets.ts | 15 + src/api/handleApiErrorString.ts | 14 + src/api/handleApiResponse.ts | 16 + src/api/handleSearchParams.ts | 17 + src/api/mfAuth.ts | 25 + src/api/patchDisbursementStatus.ts | 25 + src/api/patchOrgInfo.ts | 50 + src/api/patchPaymentsRetry.ts | 20 + src/api/patchProfileInfo.ts | 32 + src/api/patchUserRole.ts | 23 + src/api/patchUserStatus.ts | 22 + src/api/postAssets.ts | 25 + src/api/postDisbursement.ts | 24 + src/api/postDisbursementFile.ts | 24 + src/api/postForgotPassword.ts | 20 + src/api/postResetPassword.ts | 25 + src/api/postUser.ts | 24 + src/assets/logo-euroc.png | Bin 0 -> 5103 bytes src/assets/logo-usdc.png | Bin 0 -> 5334 bytes src/assets/logo-xlm.png | Bin 0 -> 2505 bytes src/components/AccountBalances.tsx | 24 + src/components/AssetAmount/index.tsx | 54 + src/components/AssetAmount/styles.scss | 24 + src/components/Breadcrumbs/index.tsx | 34 + src/components/Breadcrumbs/styles.scss | 25 + src/components/CopyWithIcon/index.tsx | 36 + src/components/CopyWithIcon/styles.scss | 21 + src/components/CsvPreview/index.tsx | 87 + src/components/CsvPreview/styles.scss | 38 + src/components/CsvUpload/index.tsx | 45 + src/components/CsvUpload/styles.scss | 14 + src/components/CsvUploadButton/index.tsx | 72 + src/components/CsvUploadButton/styles.scss | 29 + src/components/DashboardAnalytics.tsx | 162 + src/components/DisbursementButtons/index.tsx | 226 + .../DisbursementButtons/styles.scss | 14 + src/components/DisbursementDetails/index.tsx | 320 + .../DisbursementDetails/styles.scss | 22 + .../DisbursementInstructions/index.tsx | 98 + .../DisbursementInstructions/styles.scss | 17 + src/components/DisbursementsTable.tsx | 182 + src/components/DropdownMenu/index.tsx | 72 + src/components/DropdownMenu/styles.scss | 50 + src/components/ExpandContent/index.tsx | 45 + src/components/ExpandContent/styles.scss | 46 + src/components/FileUpload/index.tsx | 153 + src/components/FileUpload/styles.scss | 35 + src/components/FilterMenu/index.tsx | 115 + src/components/FilterMenu/styles.scss | 30 + src/components/InfoTooltip/index.tsx | 30 + src/components/InfoTooltip/styles.scss | 35 + src/components/InnerPage/index.tsx | 185 + src/components/InnerPage/styles.scss | 99 + src/components/MoreMenuButton.tsx | 7 + src/components/MultipleAmounts/index.tsx | 41 + src/components/MultipleAmounts/styles.scss | 31 + src/components/NewDisbursementButton.tsx | 26 + src/components/NewUserModal.tsx | 223 + .../NotificationWithButtons/index.tsx | 37 + .../NotificationWithButtons/styles.scss | 17 + src/components/PageHeader/index.tsx | 78 + src/components/PageHeader/styles.scss | 115 + src/components/Pagination/index.tsx | 70 + src/components/Pagination/styles.scss | 52 + src/components/PaymentStatus/index.tsx | 23 + src/components/PaymentStatus/styles.scss | 7 + src/components/PaymentsTable.tsx | 147 + src/components/PrivateRoute.tsx | 43 + src/components/QueryStatusHandler.tsx | 37 + src/components/ReceiverStatus/index.tsx | 23 + src/components/ReceiverStatus/styles.scss | 7 + src/components/ReceiverWalletBalance.tsx | 59 + src/components/ReceiverWalletHistory.tsx | 151 + src/components/ReceiversTable.tsx | 152 + src/components/RetryFailedPayment.tsx | 73 + src/components/SearchInput/index.tsx | 61 + src/components/SearchInput/styles.scss | 48 + src/components/SectionHeader/index.tsx | 30 + src/components/SectionHeader/styles.scss | 35 + src/components/SettingsTeamMembers.tsx | 267 + src/components/SettingsTimezone.tsx | 143 + src/components/ShowForRoles.tsx | 16 + src/components/Table/index.tsx | 167 + src/components/Table/styles.scss | 156 + src/components/Toast/index.tsx | 37 + src/components/Toast/styles.scss | 3 + src/components/UserSession.tsx | 86 + src/components/WalletTrustlines/index.tsx | 450 + src/components/WalletTrustlines/styles.scss | 33 + src/constants/settings.ts | 204 + src/generated/gitInfo.ts | 1 + src/helpers/capitalizeString.ts | 2 + src/helpers/createUrlSearchParamsString.ts | 11 + src/helpers/endSessionIfTokenInvalid.ts | 13 + src/helpers/formatDisbursements.ts | 38 + src/helpers/formatIntlDateTime.ts | 27 + src/helpers/formatIntlNumber.ts | 20 + src/helpers/formatReceivers.ts | 18 + src/helpers/formatUkrainianPhoneNumber.ts | 14 + src/helpers/formatUploadedFileDisplayName.tsx | 15 + src/helpers/getAppVersion.ts | 3 + src/helpers/getCurrentPageItems.ts | 28 + src/helpers/getInstructionsFile.ts | 17 + src/helpers/getPluralizedText.ts | 25 + src/helpers/parseApiError.ts | 14 + src/helpers/parseJwt.ts | 11 + src/helpers/refreshSessionToken.ts | 5 + src/helpers/removeFalsyKeys.ts | 10 + src/helpers/renderNumberOrDash.ts | 9 + src/helpers/sanitizeObject.ts | 6 + src/helpers/saveFile.ts | 37 + src/helpers/shortenAccountKey.ts | 2 + src/helpers/shortenString.ts | 4 + src/helpers/singleSingOn.ts | 29 + src/helpers/userRoleText.ts | 16 + src/hooks/useDownloadCsvFile.ts | 46 + src/hooks/useIsUserRoleAccepted.ts | 10 + src/hooks/useOrgAccountInfo.ts | 16 + src/hooks/useRedux.ts | 30 + src/hooks/useScrollToTop.ts | 11 + src/hooks/useSessionToken.ts | 6 + src/hooks/useSort.ts | 39 + src/index.html | 18 + src/index.tsx | 15 + src/pages/Analytics.tsx | 21 + src/pages/DisbursementDetails.tsx | 609 ++ src/pages/DisbursementDraftDetails.tsx | 311 + src/pages/Disbursements.tsx | 330 + src/pages/DisbursementsDrafts.tsx | 173 + src/pages/DisbursementsNew.tsx | 351 + src/pages/ForgotPassword.tsx | 107 + src/pages/Help.tsx | 71 + src/pages/Home.tsx | 126 + src/pages/MFAuth.tsx | 168 + src/pages/NotFound.tsx | 23 + src/pages/PaymentDetails.tsx | 357 + src/pages/Payments.tsx | 262 + src/pages/Profile.tsx | 594 ++ src/pages/ReceiverDetails.tsx | 541 + src/pages/Receivers.tsx | 300 + src/pages/Redirect.tsx | 18 + src/pages/ResetPassword.tsx | 199 + src/pages/Settings.tsx | 117 + src/pages/SignIn.tsx | 189 + src/pages/Unauthorized.tsx | 15 + src/pages/Wallets.tsx | 109 + src/setupTests.ts | 5 + src/store/ducks/assets.ts | 59 + src/store/ducks/countries.ts | 63 + src/store/ducks/disbursementDetails.ts | 261 + src/store/ducks/disbursementDrafts.ts | 236 + src/store/ducks/disbursements.ts | 131 + src/store/ducks/forgotPassword.ts | 96 + src/store/ducks/organization.ts | 215 + src/store/ducks/paymentDetails.ts | 197 + src/store/ducks/payments.ts | 124 + src/store/ducks/profile.ts | 141 + src/store/ducks/receiverDetails.ts | 135 + src/store/ducks/receiverPayments.ts | 143 + src/store/ducks/receivers.ts | 125 + src/store/ducks/singleSignOnUserAccount.ts | 29 + src/store/ducks/statistics.ts | 85 + src/store/ducks/userAccount.ts | 222 + src/store/ducks/users.ts | 250 + src/store/ducks/wallets.ts | 58 + src/store/index.ts | 85 + src/styles-utils.scss | 12 + src/styles.scss | 675 ++ src/types/@modules.d.ts | 11 + src/types/index.ts | 937 ++ tsconfig.json | 14 + webpack.common.js | 157 + webpack.dev.js | 15 + webpack.prod.js | 7 + yarn.lock | 9218 +++++++++++++++++ 223 files changed, 26725 insertions(+) create mode 100644 .dockerignore create mode 100644 .eslintignore create mode 100644 .eslintrc.json create mode 100644 .github/workflows/docker_image_public_release.yml create mode 100644 .github/workflows/test-build.yml create mode 100644 .gitignore create mode 100644 .husky/.gitignore create mode 100755 .husky/post-merge create mode 100755 .husky/pre-commit create mode 100644 .prettierignore create mode 100644 .prettierrc.json create mode 100644 CHANGELOG.md create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 babel.config.js create mode 100644 nginx.conf create mode 100644 package.json create mode 100644 public/favicon.ico create mode 100644 public/logo192.png create mode 100644 public/logo512.png create mode 100644 public/manifest.json create mode 100644 public/resources/disbursement-template.csv create mode 100644 public/robots.txt create mode 100644 src/App.tsx create mode 100644 src/api/authLogin.ts create mode 100644 src/api/authRefreshToken.ts create mode 100644 src/api/deleteAsset.ts create mode 100644 src/api/getAssets.ts create mode 100644 src/api/getCountries.ts create mode 100644 src/api/getDisbursementDetails.ts create mode 100644 src/api/getDisbursementDrafts.ts create mode 100644 src/api/getDisbursementInstructions.ts create mode 100644 src/api/getDisbursementReceivers.ts create mode 100644 src/api/getDisbursements.ts create mode 100644 src/api/getOrgInfo.ts create mode 100644 src/api/getOrgLogo.ts create mode 100644 src/api/getPaymentDetails.ts create mode 100644 src/api/getPayments.ts create mode 100644 src/api/getProfileInfo.ts create mode 100644 src/api/getReceiverDetails.ts create mode 100644 src/api/getReceivers.ts create mode 100644 src/api/getStatistics.ts create mode 100644 src/api/getStellarAccountInfo.ts create mode 100644 src/api/getStellarAccountPayments.ts create mode 100644 src/api/getStellarTransaction.ts create mode 100644 src/api/getUsers.ts create mode 100644 src/api/getWallets.ts create mode 100644 src/api/handleApiErrorString.ts create mode 100644 src/api/handleApiResponse.ts create mode 100644 src/api/handleSearchParams.ts create mode 100644 src/api/mfAuth.ts create mode 100644 src/api/patchDisbursementStatus.ts create mode 100644 src/api/patchOrgInfo.ts create mode 100644 src/api/patchPaymentsRetry.ts create mode 100644 src/api/patchProfileInfo.ts create mode 100644 src/api/patchUserRole.ts create mode 100644 src/api/patchUserStatus.ts create mode 100644 src/api/postAssets.ts create mode 100644 src/api/postDisbursement.ts create mode 100644 src/api/postDisbursementFile.ts create mode 100644 src/api/postForgotPassword.ts create mode 100644 src/api/postResetPassword.ts create mode 100644 src/api/postUser.ts create mode 100644 src/assets/logo-euroc.png create mode 100644 src/assets/logo-usdc.png create mode 100644 src/assets/logo-xlm.png create mode 100644 src/components/AccountBalances.tsx create mode 100644 src/components/AssetAmount/index.tsx create mode 100644 src/components/AssetAmount/styles.scss create mode 100644 src/components/Breadcrumbs/index.tsx create mode 100644 src/components/Breadcrumbs/styles.scss create mode 100644 src/components/CopyWithIcon/index.tsx create mode 100644 src/components/CopyWithIcon/styles.scss create mode 100644 src/components/CsvPreview/index.tsx create mode 100644 src/components/CsvPreview/styles.scss create mode 100644 src/components/CsvUpload/index.tsx create mode 100644 src/components/CsvUpload/styles.scss create mode 100644 src/components/CsvUploadButton/index.tsx create mode 100644 src/components/CsvUploadButton/styles.scss create mode 100644 src/components/DashboardAnalytics.tsx create mode 100644 src/components/DisbursementButtons/index.tsx create mode 100644 src/components/DisbursementButtons/styles.scss create mode 100644 src/components/DisbursementDetails/index.tsx create mode 100644 src/components/DisbursementDetails/styles.scss create mode 100644 src/components/DisbursementInstructions/index.tsx create mode 100644 src/components/DisbursementInstructions/styles.scss create mode 100644 src/components/DisbursementsTable.tsx create mode 100644 src/components/DropdownMenu/index.tsx create mode 100644 src/components/DropdownMenu/styles.scss create mode 100644 src/components/ExpandContent/index.tsx create mode 100644 src/components/ExpandContent/styles.scss create mode 100644 src/components/FileUpload/index.tsx create mode 100644 src/components/FileUpload/styles.scss create mode 100644 src/components/FilterMenu/index.tsx create mode 100644 src/components/FilterMenu/styles.scss create mode 100644 src/components/InfoTooltip/index.tsx create mode 100644 src/components/InfoTooltip/styles.scss create mode 100644 src/components/InnerPage/index.tsx create mode 100644 src/components/InnerPage/styles.scss create mode 100644 src/components/MoreMenuButton.tsx create mode 100644 src/components/MultipleAmounts/index.tsx create mode 100644 src/components/MultipleAmounts/styles.scss create mode 100644 src/components/NewDisbursementButton.tsx create mode 100644 src/components/NewUserModal.tsx create mode 100644 src/components/NotificationWithButtons/index.tsx create mode 100644 src/components/NotificationWithButtons/styles.scss create mode 100644 src/components/PageHeader/index.tsx create mode 100644 src/components/PageHeader/styles.scss create mode 100644 src/components/Pagination/index.tsx create mode 100644 src/components/Pagination/styles.scss create mode 100644 src/components/PaymentStatus/index.tsx create mode 100644 src/components/PaymentStatus/styles.scss create mode 100644 src/components/PaymentsTable.tsx create mode 100644 src/components/PrivateRoute.tsx create mode 100644 src/components/QueryStatusHandler.tsx create mode 100644 src/components/ReceiverStatus/index.tsx create mode 100644 src/components/ReceiverStatus/styles.scss create mode 100644 src/components/ReceiverWalletBalance.tsx create mode 100644 src/components/ReceiverWalletHistory.tsx create mode 100644 src/components/ReceiversTable.tsx create mode 100644 src/components/RetryFailedPayment.tsx create mode 100644 src/components/SearchInput/index.tsx create mode 100644 src/components/SearchInput/styles.scss create mode 100644 src/components/SectionHeader/index.tsx create mode 100644 src/components/SectionHeader/styles.scss create mode 100644 src/components/SettingsTeamMembers.tsx create mode 100644 src/components/SettingsTimezone.tsx create mode 100644 src/components/ShowForRoles.tsx create mode 100644 src/components/Table/index.tsx create mode 100644 src/components/Table/styles.scss create mode 100644 src/components/Toast/index.tsx create mode 100644 src/components/Toast/styles.scss create mode 100644 src/components/UserSession.tsx create mode 100644 src/components/WalletTrustlines/index.tsx create mode 100644 src/components/WalletTrustlines/styles.scss create mode 100644 src/constants/settings.ts create mode 100644 src/generated/gitInfo.ts create mode 100644 src/helpers/capitalizeString.ts create mode 100644 src/helpers/createUrlSearchParamsString.ts create mode 100644 src/helpers/endSessionIfTokenInvalid.ts create mode 100644 src/helpers/formatDisbursements.ts create mode 100644 src/helpers/formatIntlDateTime.ts create mode 100644 src/helpers/formatIntlNumber.ts create mode 100644 src/helpers/formatReceivers.ts create mode 100644 src/helpers/formatUkrainianPhoneNumber.ts create mode 100644 src/helpers/formatUploadedFileDisplayName.tsx create mode 100644 src/helpers/getAppVersion.ts create mode 100644 src/helpers/getCurrentPageItems.ts create mode 100644 src/helpers/getInstructionsFile.ts create mode 100644 src/helpers/getPluralizedText.ts create mode 100644 src/helpers/parseApiError.ts create mode 100644 src/helpers/parseJwt.ts create mode 100644 src/helpers/refreshSessionToken.ts create mode 100644 src/helpers/removeFalsyKeys.ts create mode 100644 src/helpers/renderNumberOrDash.ts create mode 100644 src/helpers/sanitizeObject.ts create mode 100644 src/helpers/saveFile.ts create mode 100644 src/helpers/shortenAccountKey.ts create mode 100644 src/helpers/shortenString.ts create mode 100644 src/helpers/singleSingOn.ts create mode 100644 src/helpers/userRoleText.ts create mode 100644 src/hooks/useDownloadCsvFile.ts create mode 100644 src/hooks/useIsUserRoleAccepted.ts create mode 100644 src/hooks/useOrgAccountInfo.ts create mode 100644 src/hooks/useRedux.ts create mode 100644 src/hooks/useScrollToTop.ts create mode 100644 src/hooks/useSessionToken.ts create mode 100644 src/hooks/useSort.ts create mode 100644 src/index.html create mode 100644 src/index.tsx create mode 100644 src/pages/Analytics.tsx create mode 100644 src/pages/DisbursementDetails.tsx create mode 100644 src/pages/DisbursementDraftDetails.tsx create mode 100644 src/pages/Disbursements.tsx create mode 100644 src/pages/DisbursementsDrafts.tsx create mode 100644 src/pages/DisbursementsNew.tsx create mode 100644 src/pages/ForgotPassword.tsx create mode 100644 src/pages/Help.tsx create mode 100644 src/pages/Home.tsx create mode 100644 src/pages/MFAuth.tsx create mode 100644 src/pages/NotFound.tsx create mode 100644 src/pages/PaymentDetails.tsx create mode 100644 src/pages/Payments.tsx create mode 100644 src/pages/Profile.tsx create mode 100644 src/pages/ReceiverDetails.tsx create mode 100644 src/pages/Receivers.tsx create mode 100644 src/pages/Redirect.tsx create mode 100644 src/pages/ResetPassword.tsx create mode 100644 src/pages/Settings.tsx create mode 100644 src/pages/SignIn.tsx create mode 100644 src/pages/Unauthorized.tsx create mode 100644 src/pages/Wallets.tsx create mode 100644 src/setupTests.ts create mode 100644 src/store/ducks/assets.ts create mode 100644 src/store/ducks/countries.ts create mode 100644 src/store/ducks/disbursementDetails.ts create mode 100644 src/store/ducks/disbursementDrafts.ts create mode 100644 src/store/ducks/disbursements.ts create mode 100644 src/store/ducks/forgotPassword.ts create mode 100644 src/store/ducks/organization.ts create mode 100644 src/store/ducks/paymentDetails.ts create mode 100644 src/store/ducks/payments.ts create mode 100644 src/store/ducks/profile.ts create mode 100644 src/store/ducks/receiverDetails.ts create mode 100644 src/store/ducks/receiverPayments.ts create mode 100644 src/store/ducks/receivers.ts create mode 100644 src/store/ducks/singleSignOnUserAccount.ts create mode 100644 src/store/ducks/statistics.ts create mode 100644 src/store/ducks/userAccount.ts create mode 100644 src/store/ducks/users.ts create mode 100644 src/store/ducks/wallets.ts create mode 100644 src/store/index.ts create mode 100644 src/styles-utils.scss create mode 100644 src/styles.scss create mode 100644 src/types/@modules.d.ts create mode 100644 src/types/index.ts create mode 100644 tsconfig.json create mode 100644 webpack.common.js create mode 100644 webpack.dev.js create mode 100644 webpack.prod.js create mode 100644 yarn.lock diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..9e05159 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +node_modules +dist +.tmp diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..0c4524c --- /dev/null +++ b/.eslintignore @@ -0,0 +1,13 @@ +babel.config.js +webpack.config.js +webpack.common.js +webpack.dev.js +webpack.prod.js +node_modules/ +dist/ +build/ +.prettierrc.json +.eslintrc.json +prettier.config.js +.eslintrc.js +env.d.ts diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..7298088 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,51 @@ +{ + "extends": [ + // By extending from a plugin config, we can get recommended rules without having to add them manually. + "eslint:recommended", + // "plugin:react/recommended", + // React v17+ doesn't need to have React imported in every file, it works globaly. + // "plugin:react/jsx-runtime", + "plugin:react-hooks/recommended", + "plugin:import/recommended", + "plugin:jsx-a11y/recommended", + "plugin:@typescript-eslint/recommended", + // This disables the formatting rules in ESLint that Prettier is going to be responsible for handling. + // Make sure it's always the last config, so it gets the chance to override other configs. + "eslint-config-prettier" + ], + "settings": { + "react": { + // Tells eslint-plugin-react to automatically detect the version of React to use. + "version": "detect" + }, + "import/parsers": { + "@typescript-eslint/parser": [".ts", ".tsx"] + }, + // Tells eslint how to resolve imports + "import/resolver": { + "node": { + "paths": ["src"], + "extensions": [".js", ".jsx", ".ts", ".tsx"] + }, + "typescript": { + "project": "@stellar/*/tsconfig.json" + } + } + }, + "rules": { + "@typescript-eslint/ban-ts-comment": [ + "error", + { "ts-ignore": "allow-with-description" } + ], + // TODO: ideally, these should be removed + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", + "jsx-a11y/click-events-have-key-events": "off", + "jsx-a11y/interactive-supports-focus": "off", + "jsx-a11y/label-has-associated-control": "off", + "react/prop-types": "off", + "react/jsx-key": "off", + "react/no-unescaped-entities": "off", + "import/named": "off" + } +} diff --git a/.github/workflows/docker_image_public_release.yml b/.github/workflows/docker_image_public_release.yml new file mode 100644 index 0000000..a4d3872 --- /dev/null +++ b/.github/workflows/docker_image_public_release.yml @@ -0,0 +1,97 @@ +# This workflow publishes a new docker image to 'https://hub.docker.com/r/stellar/stellar-disbursement-platform-frontend' +# when a new release is created or when we merge something to the develop branch. +name: Docker Image Public Release + +on: + release: + types: + - published + push: + branches: + - develop + +jobs: + test-build: + uses: ./.github/workflows/test-build.yml # execute the callable test-build.yml + secrets: inherit # pass all secrets + + build_and_push_docker_image_on_release: + if: github.event_name == 'release' + name: Push to DockerHub (release prd) # stellar/stellar-disbursement-platform-frontend:{VERSION} + runs-on: ubuntu-latest + needs: + - test-build + steps: + - name: Check if tag is not empty + run: | + if [[ -z "${{ github.event.release.tag_name }}" ]]; then + echo "Release tag name cannot be empty." + exit 1 + fi + + - uses: actions/checkout@v3 + + - name: Login to DockerHub + uses: docker/login-action@v2.2.0 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push to DockerHub (release prd) + uses: docker/build-push-action@v4.1.1 + with: + push: true + build-args: | + GIT_COMMIT=${{ github.event.release.tag_name }} + tags: stellar/stellar-disbursement-platform-frontend:${{github.event.release.tag_name}},stellar/stellar-disbursement-platform-frontend:latest + file: Dockerfile + + build_and_push_docker_image_on_dev_push: + if: github.event_name == 'push' && github.ref == 'refs/heads/develop' + name: Push to DockerHub (release develop branch) # stellar/stellar-disbursement-platform-frontend:edge-{DATE}-{SHA} + runs-on: ubuntu-latest + needs: + - test-build + steps: + - uses: actions/checkout@v3 + + - name: Login to DockerHub + uses: docker/login-action@v2.2.0 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Get current date + id: get_date + run: echo "DATE=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT + + - name: Get SHA + shell: bash + id: get_sha + run: + echo "SHA=$(git rev-parse --short ${{ github.sha }} )" >> + $GITHUB_OUTPUT + + - name: Build and push to DockerHub (develop branch) + uses: docker/build-push-action@v4.1.1 + with: + push: true + build-args: | + GIT_COMMIT=${{ steps.get_sha.outputs.SHA }} + tags: + stellar/stellar-disbursement-platform-frontend:edge,stellar/stellar-disbursement-platform-frontend:edge-${{steps.get_date.outputs.DATE + }}-${{ steps.get_sha.outputs.SHA }} + file: Dockerfile + + complete: + if: always() + needs: + - build_and_push_docker_image_on_release + - build_and_push_docker_image_on_dev_push + runs-on: ubuntu-latest + steps: + - if: + contains(needs.*.result, 'failure') || contains(needs.*.result, + 'cancelled') + run: exit 1 + # TODO: figure out which job failed and print the logs diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml new file mode 100644 index 0000000..641f00b --- /dev/null +++ b/.github/workflows/test-build.yml @@ -0,0 +1,28 @@ +name: Test and build + +on: + push: + branches: [main] + pull_request: + workflow_call: # allows this workflow to be called from another workflow + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v2 + with: + node-version: 18 + - run: yarn install + - run: yarn build + + complete: + if: always() + needs: [build] + runs-on: ubuntu-latest + steps: + - if: + contains(needs.*.result, 'failure') || contains(needs.*.result, + 'cancelled') + run: exit 1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..092cc4c --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.idea/ + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env +.env.local +.env.development.local +.env.test.local +.env.production.local +.nvmrc + +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.eslintcache + +# env variables +/public/settings/env-config.js diff --git a/.husky/.gitignore b/.husky/.gitignore new file mode 100644 index 0000000..31354ec --- /dev/null +++ b/.husky/.gitignore @@ -0,0 +1 @@ +_ diff --git a/.husky/post-merge b/.husky/post-merge new file mode 100755 index 0000000..2744386 --- /dev/null +++ b/.husky/post-merge @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +yarn install-if-package-changed diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..025779e --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +yarn pre-commit diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..8364976 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +# Ignore artifacts: +dist +build +coverage diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..d90ebd4 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,12 @@ +{ + "arrowParens:": "always", + "bracketSpacing": true, + "jsxBracketSameLine": false, + "printWidth": 80, + "proseWrap": "always", + "semi": true, + "singleQuote": false, + "tabWidth": 2, + "trailingComma": "all", + "useTabs": false +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..c41e16d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,25 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), + +## [1.0.0](https://github.com/stellar/stellar-relief-backoffice/tree/1.0.0) + +### Added + +- The payment detail to display the cash-out status per payment. +- The account status to be able to track the cash-out status per account. + +### Updated + +- The account & disbursement detail pages to display the amount cashed-out per + account and per disbursement. + +## {version} < 1.0.0 + +### Added: + +- Disbursements list & detail. +- Beneficiaries (accounts) list & detail. +- Payments per disbursement detail and per account detail. diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..404f23f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ +FROM ubuntu:20.04 as build + +LABEL maintainer="SDF Ops Team " + +RUN mkdir -p /app +WORKDIR /app + +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update && apt-get install --no-install-recommends -y gpg curl git make g++ ca-certificates apt-transport-https && \ + curl -sSL https://deb.nodesource.com/gpgkey/nodesource.gpg.key|gpg --dearmor >/etc/apt/trusted.gpg.d/nodesource.gpg && \ + echo "deb https://deb.nodesource.com/node_18.x focal main" | tee /etc/apt/sources.list.d/nodesource.list && \ + curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg |gpg --dearmor >/etc/apt/trusted.gpg.d/yarnpkg.gpg && \ + echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ + apt-get update && apt-get install -y nodejs yarn && apt-get clean + + +COPY . /app/ +RUN yarn install +RUN yarn build + +FROM nginx:1.17 + +COPY --from=build /app/build/ /usr/share/nginx/html/ +COPY --from=build /app/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7a4a3ea --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..04c4e74 --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +# Check if we need to prepend docker commands with sudo +SUDO := $(shell docker version >/dev/null 2>&1 || echo "sudo") + +# If LABEL is not provided set default value +LABEL ?= $(shell git rev-parse --short HEAD)$(and $(shell git status -s),-dirty-$(shell id -u -n)) +# If TAG is not provided set default value +TAG ?= stellar/disbursement-platform-frontend:$(LABEL) +# https://github.com/opencontainers/image-spec/blob/master/annotations.md +BUILD_DATE := $(shell date -u +%FT%TZ) + +docker-build: + $(SUDO) docker build --pull --label org.opencontainers.image.created="$(BUILD_DATE)" -t $(TAG) . + +docker-push: + $(SUDO) docker push $(TAG) diff --git a/README.md b/README.md new file mode 100644 index 0000000..0237f05 --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +# stellar-relief-backoffice + +## Add `/public/settings/env-config.js` file locally with the following keys: + +### SSO + +- USE_SSO - variable for switch to current/old Login or to SSO Login; +- If you are going to use SSO - you need provide OIDC_REDIRECT_URI to specialist + who will configure OIDC Provider and get from them OIDC_AUTHORITY, + OIDC_CLIENT_ID, OIDC_SCOPE, OIDC_USERNAME_MAPPING; +- OIDC_USERNAME_MAPPING - is using for show in web page in "username" field; +- Options of OIDC_USERNAME_MAPPING you could find in ID Token body (in user + claims) or in OIDC Provider configure page; +- When you will switch to using SSO - it must be synchronously changed in + BackEnd side - as in current moment its possible to use only tokens from one + issuer; + +```javascript +window._env_ = { + API_URL: "", + STELLAR_EXPERT_URL: "", + HORIZON_URL: "", + USDC_ASSET_ISSUER: "", + RECAPTCHA_SITE_KEY: "", + + USE_SSO: false, + OIDC_AUTHORITY: + "https://.b2clogin.com/.onmicrosoft.com/", + OIDC_CLIENT_ID: "", + OIDC_REDIRECT_URI: "http://localhost:3000/signin-oidc", + OIDC_SCOPE: "openid", + OIDC_USERNAME_MAPPING: "name", +}; +``` diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..c742e96 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,22 @@ +module.exports = { + presets: [ + "@babel/preset-react", + "@babel/preset-typescript", + [ + "@babel/preset-env", + { + targets: { + browsers: "last 2 versions", + }, + modules: false, + loose: false, + }, + ], + ], + plugins: ["transform-class-properties", "react-hot-loader/babel"], + env: { + test: { + plugins: ["transform-es2015-modules-commonjs"], + }, + }, +}; diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..2c513fb --- /dev/null +++ b/nginx.conf @@ -0,0 +1,23 @@ +server { + listen 80; + server_name localhost; + + gzip on; + gzip_disable "msie6"; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_buffers 16 8k; + gzip_types application/javascript application/rss+xml application/vnd.ms-fontobject application/x-font application/x-font-opentype application/x-font-otf application/x-font-truetype application/x-font-ttf application/x-javascript application/xhtml+xml application/xml font/opentype font/otf font/ttf image/svg+xml image/x-icon text/css text/javascript text/plain text/xml; + + location / { + root /usr/share/nginx/html; + try_files $uri /index.html index.htm; + gzip_static on; + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..2faa6b1 --- /dev/null +++ b/package.json @@ -0,0 +1,119 @@ +{ + "name": "stellar-relief-backoffice", + "version": "1.0.0", + "license": "Apache-2.0", + "engines": { + "node": ">=18.x" + }, + "lint-staged": { + "src/**/*.ts?(x)": [ + "eslint --fix --max-warnings 0" + ] + }, + "private": true, + "dependencies": { + "@reduxjs/toolkit": "^1.9.5", + "@stellar/design-system": "^1.0.0-beta.14", + "@stellar/tsconfig": "^1.0.2", + "@svgr/webpack": "8.0.1", + "@tanstack/react-query": "^4.29.25", + "@testing-library/jest-dom": "^5.17.0", + "@testing-library/react": "^14.0.0", + "@testing-library/user-event": "^14.4.3", + "@types/jest": "^29.5.3", + "@types/lodash": "^4.14.195", + "@types/node": "^20.4.2", + "@types/react": "^18.2.15", + "@types/react-dom": "^18.2.7", + "@types/react-google-recaptcha": "^2.1.5", + "@types/react-redux": "^7.1.25", + "@types/react-router-dom": "^5.3.3", + "@types/uuid": "^9.0.2", + "@typescript-eslint/eslint-plugin": "^6.1.0", + "@typescript-eslint/parser": "^6.1.0", + "assert": "^2.0.0", + "bignumber.js": "^9.1.1", + "buffer": "^6.0.3", + "concurrently": "^8.2.0", + "crypto-browserify": "^3.12.0", + "eslint": "^8.45.0", + "eslint-config-prettier": "^8.8.0", + "eslint-config-react": "^1.1.7", + "eslint-config-react-app": "^7.0.1", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-prefer-arrow": "^1.2.3", + "eslint-plugin-react": "^7.32.2", + "eslint-plugin-react-hooks": "^4.6.0", + "https-browserify": "^1.0.0", + "husky": "^8.0.3", + "lint-staged": "^13.2.3", + "lodash": "^4.17.21", + "node-sass": "^9.0.0", + "oidc-client-ts": "^2.2.4", + "os-browserify": "^0.3.0", + "papaparse": "^5.4.1", + "prettier": "^2.8.7", + "pretty-quick": "^3.1.3", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-google-recaptcha": "^3.1.0", + "react-redux": "^8.1.1", + "react-router-dom": "^6.14.2", + "redux": "^4.2.1", + "sass": "^1.64.0", + "sass-loader": "^13.3.2", + "stream-browserify": "^3.0.0", + "stream-http": "^3.2.0", + "typescript": "^5.1.6", + "url": "^0.11.1" + }, + "scripts": { + "start": "yarn git-info && webpack serve --open --config webpack.dev.js", + "build": "yarn git-info && NODE_ENV=production webpack --config webpack.prod.js", + "install-if-package-changed": "git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD | grep --quiet yarn.lock && yarn install || exit 0", + "prod:build": "docker image build -t disbursement-platform-frontend:localbuild .", + "prod:serve": "docker run -p 8000:80 disbursement-platform-frontend:localbuild", + "production": "yarn prod:build && yarn prod:serve", + "prepare": "husky install", + "pre-commit": "concurrently 'pretty-quick --staged' 'lint-staged' 'tsc --noEmit'", + "git-info": "rm -rf src/generated/ && mkdir src/generated/ && echo export default \"{\\\"commitHash\\\": \\\"$(git rev-parse --short HEAD)\\\"};\" > src/generated/gitInfo.ts" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "devDependencies": { + "@tanstack/eslint-plugin-query": "^4.29.25", + "@types/papaparse": "^5.3.7", + "clean-webpack-plugin": "^4.0.0", + "copy-webpack-plugin": "^11.0.0", + "css-loader": "^6.8.1", + "eslint-webpack-plugin": "^4.0.1", + "file-loader": "^6.2.0", + "fork-ts-checker-webpack-plugin": "^8.0.0", + "html-webpack-plugin": "^5.5.3", + "mini-css-extract-plugin": "^2.7.6", + "react-hot-loader": "^4.13.1", + "style-loader": "^3.3.3", + "ts-loader": "^9.4.4", + "tsconfig-paths-webpack-plugin": "^4.1.0", + "webpack": "^5.88.2", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^4.15.1" + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..4f17c94a834735ea04cf72bff9589bf3f0a8bbcd GIT binary patch literal 7406 zcmeI02T)Yk8pr=j?<@-}uz<9stjmIgm8B`gf^-lRMWZM|0l_P1Ac9H}u-vCUL5x_j zqX-tF*fn)hCsi{^Y?<`ldwb`*?82`2GRe%FH}mFkW_IuS&iVf5o;~;MJ>TyGL@>sf zF<@5_~MIjcX!A8@4t_uM~`Ch;>Gywx8LySqmLpvIT^OL zw%ECICkhG*AeYPW#TQ?oudff))zyfJiNUkaK8v^Cej7jj_#-Y}yombxdQ6-+5f&B} zc=gp+F>BT=czJo@W4PJl!b?n%& z19Rujg`b}vKL7l4oH}(1(b3U(=9y=(VZ#PwXJ^CN*%^24+`)kZ2T)vGj30jZ0d;kC zm@r`i%+1ZQb?a7q^wCGCsHngbPdtIOYuB>pCdONDy@fq{_Mot^5P^Y#`1c&Ah(sbh|NQgF&CP|Yt1I4l=N%kAd>Emjq4@ddpK8Chx;slm0TZYKUNH{t=;?}KO*tc&VzWeSwoI7_82?+@> zH8sUcFTI2EE?6Jqt($a#IloZ(6+2M^h z-oUP1yD)FwJbd}(mxzsx9r`1T)J9g|KfeO)UTNy4CUu%u`(GJbtVyuzXwA!O?XXMG zu$THhN{mmAu2o!Dqu>XNqNeU%3g@D%e|8Cq2O2$?v*RXDx%})rM^@!bFu7Te< zHZ_tdy4+n%j+@0LcJ}smx;j_1B=LM-U9axux~pU>8`b1&XaQ?*J)fv+1{U3agx$@5 zn84L$FDaIsyfEZDP}?!CpLd)-d`fHlllysIG5TSzyA<2D_w#){hK;IDW{(-ai7E1q zO`T%cxorW@?;2PQUB~iu8m4Hkni0hm4Q*uTl^s!hl98Sb#5Ht3G|HSQd@EKmMR&$| zW(<|n9(>@6A(Q!c^L*@mdsIyEz_}o{>ao_9%+QrZF1(^vXV7&;gd1}zk~QT6B@+7% zG9H=93~f>J{48BvxVB$SWjLe1>ZM zgI3JxfVW!86lW~M$hc%Hh4dh=*fZR}7t+I*s+m)m<(YUus!ln;46A+XRm1%=V|mX` zHbifxLppO>dtx$E^e&%I^4TdNd|ngl)GM3a_)V^Y-MnSm73S1eYFxq;SC9HJgOzeU zXI9;q#XCA{oARB@TA9a$?0TkXE*6oTUlw4vNoVnV#o!S6!H*O%pNcJt$`_`R_|wu&JD7|2EARoc>dTTgC@n;zRkHDW9X{2{=)nGF5TZdFYXeLm?JCjzqA5D zY_i_$6VE<_oNB@hUD4xIit~vLh#iSJiNAa4 zB)%dxAr>OOBnBa_B`zeUBF-izA?_r8B~~P6BGzngZxFxQ7^;7?F7L>eZ_P zTM^3;M-d~pwY3Rs9vmEurluym@WKlMrxWiIHxv62I}&#ia}kdd!$0@jbLi>m5g3g4 zkC=YbrcDAv5oZ#Y5la!D6W0^t66XTOjcFV|hWCi{UE1;Ii)WdG03smB!TTM$ym}WKIFd!@RQz@B7HnuvQTP_wa z=hDMPGQB}$2@BFPl<<{?=4Shwn)+MiHj0b%;(T>ZDHk)xrAod+8+47X8^;;xIV4Jo zeYm8Gg+nuQN#RBf-l8hnDRIiod@d`ha?rzNTzZ3U3bV`0CluDNn4HBqWJcF(TjN8j zS81zq4{mO%oxHxX#)5MzupICh?PzAK?T7WuM$X&WvrO$()Wnr8l?Wc$+)#eSH;ju3 zSrD*9sh%ON<(9?HV=K0pORdrk;8dO0pjg8NKBQ4rnVN)hE3->rpBFw`*FQU4oPm<; zm0YNaX_ZnF5y-7ki1MnPbp2JSoIj8_FLoJME1jWME(ur=62pc0>iQAOSy8=S66C`* z6?v)4Jn#4BCb~}5IT)Me4yZoSx4|I)ZwAFFlw0v;pTRgqFE(L~LZRFy6*{l!?4+}ua^#fr zrF<@(;S_u9-n|>Iyz+{W7o|Ka#Wi%kQfxr^UCMFNIZt`!oSYn7xNt$pky6YSj0E(ZfRKDKZ_SCWo=s zQX9FKA5@_(Mr0dBhN}GiyyQ00ps{4DrKTcJnT3brXgfDoW`{dDu+)%_%@RVE@Ut;cEPS>t7Ag08sz{ literal 0 HcmV?d00001 diff --git a/public/logo192.png b/public/logo192.png new file mode 100644 index 0000000000000000000000000000000000000000..476ff8d02ec31c87b274f5e06efa3d8df9d56b9e GIT binary patch literal 3843 zcmZ`+cTm$^v;Kt^0)(mpk&;&tP${89KnOiZktRi@*C1l7w-odKPjx}iD%R1ukv9q7+|xD(pc5C9$v0{}h}04Qfy_+l1!<9_)?_P5El#uM|d^Bz3Is#_I)u+KS@EY zzD}%yl-pg9z*qG=KT8K!w-ah;Z{|9;?3I%iDvQK*q>c|FxUWK#2Lo?G_$3YXHruCG zy1Oy;0*mJ!ESsjTd$OfDsvH{QJT(efyM%?p<73|qc-)l^a3{+5Z(N+3lzTAU|LMoB zc*)3ae!fL>8AvN^?!>LZUx@!LV^@39RYT=vN_U)vksQt{qbdUm?zJIbt?25Wx|y^F`C%|*YzaI+H>Q{PrH>MHKpGZw%9o&FCB z#Q#LVy;iax6hmxVd{JL}Cgr&M?diMXJ|m zHV?Hvb((H@mdV|)lxWTWGE-u9D*oK*1%1=-l;LdeDbD4_QBq~T#5Mi#Os;p|JxrwE z+BVk@WSqk$cFE*AHa=3y&zPP$K%!3D4*0u=xC0Cdc_i-`6#tdCB^ig8oFd*c>q!l- zv)57&Ie4j_zidIvZr&?K7W&ziIxFM{dNsK^)lR+JdxEFmljes>SF^lLnI?uvWWDRT zJaRcFBX$%7=XEPoOSY-TxwTI(Kw`zY;N_)tT$=1z0SWJ(7;JQo=k%=I!kxK>Xc$g~;1$ zY5Oxq(|ErCID3`JHi(-!ISLhye4I(IN*tO}TUk@!<9Cnk8MIUk1*~UnT9p{Z;$Z=^ z9-{re{`S%h&PVY#u+%7HuoX{AAOsiL-P#XYG3wB=pf0IDmcvZ2-(P9}=w7n5N>;^w{;5z^0YNH7+qYE3M185d3uLX05}E>*9=eRH4eYS^o4b0qSob;D@)1U=W82BTB7 zh3aM0z+><_)ySl8xJTzpyTiiPLF@Tv9F`SbNa`h3_O0OzQzF6Cnk>kMshNT&j5$*1 z(LB?2JVQ1oMQp;a*miy(&5oM4F|hsymcg)wAN;6A^I$5yXxxVoieBR-b%DfV%3F-= zFl=hx)N0^;DMK01JQK=vPBgtfEUyavmC0I1TZWanBW$@GX=a@+m;R~79bE|JWqg_? z+q010HoET_ZJ=stEryqRt6s41oTV7#N2~^@O`1Ej zi3xNTb~i22)?!F0n8^i0$<>pjwk=Wm0642}UfYCEo^aeVA_IeJ5{E9}Ql^#;3N2)mK(sNU-<92ui=Y*LWAW8$0 za1<}$>vk;v2Y|}sjc1aeR7c^~`FzS1`7-PRx0%mtENNB33ZySG*>0TtARnrnxBNBi zKahd$k!w1PL#hmqJ&AqvG`40<2OgxoKyxQW70_$M=hDt(K3*2-1DB$eJ%Iu>x$)4I z&w*DtxoN#Mc-j_4#j*Xh#QeEY*0ucQFGXKgU)&W>tWu7)Gj8uvK~mu7^%}P}7k15y zCA@6C%StmddLCS=ODM?C-JwTmfB&^M1yJ|i+>z!nZz633DCR;lqR1YL=eJrd9A7up_QZT6d4-Gpl(o%TiBlG!sas94zMc(_ zIV$%TrR=_tH*hOb{m|e+RQ7whH5bHOinA*8Y~gvHeri3H6MVSHDfEN>Sz?(us_JAj zh@>;MS1p7;p`zr6a$Vg>73x{b3Iw@H6uOY`#8U8NFyr>2vzl|W)vo~p`4~R-q-4 z)TGM5W0Zot!;J2hVU`zpyJE;Kw21Sg=4i(OWyI6F?v0~LHH$bpK73hvNET>$=@c2c z#_7RIQEyiifWlc@&0$6qT237z%Tnm;DL#(K8W#b+%CAa*nG}B*6Q_=*%?H6Uv_)aD zgb(&cVQ2Uy(#0&g5wu8cof~C7{SgGSp zU)AT&VB5aKth-5l$V*(+QbQ8?^B{D*0NaG@HbOg(b)z z`I!dAr1X|<=vGI4l~Y6}r1n9n*CsrM?xqM{*`tFc=;*IT;m%KH51QpIOp@}q-g6GS z%cOBNw~ux&67Kk*ia9B~bHJslswC_pvIUW(2NRa>VuoN?p2~rJvlAv)2)a z+Cb0TBFNr(uCS-=T`7}3?H7uk04FPLV1GxoP(NB%=(4^z>SnMzs!~X#v?&9#gWgSW zlfq{?13mN?@8!+W-jbf>UIIcj$?|{d#9VRAQ9t$XU?Z4E`h2d)B6*O%4@+|L5U=8z zE77Mo_!FCqPlJXT?^Odou<=r&SXHR>!|qT=@7*td59$k!SUK0!K~fVp0zNtDnjY`- zoptK<^~#gu^1IlXx=-sR@fQzrs;S;6jxOdo?hACt-yVXcLz!M6f166-10DCdW8W>s z`nM09F&NMBcbc=?%nDg(97E2eup#^?K70Ul`0tBty~MtH+XVj`xLO+-`JgQ5L_7~_ zD*0_B6^_lO{SBqUM4QcO=t%4Bk}Vf~@_?p%V(ZoPQ@`ws-TSs3;ROg+Sfz)LC>dYy!Qr6=_Mwh`6R@ytC8}#Dp*l@jNH4n=MyM5vtH6${*PD3-1Z@(8u!}x?)D+KvEq9P zXiU4>tYBkU%-RELXqfmb9IDN4h;k-vq_$%qmJ&LIP1bvh`%%Yunh1ph5wZWEkN#IN zJw66Y6oxG8e=dce$+#>2+E)I~4*o7kr-v?Q07xUG5#k6%afH0NloC?r-*p`!jYJ^Q zXH~KPhv4b$jBySA?}U|zsJ1hL)`7E_u|oc bHzj~oZVvw)4Y`!F6o8(#k=APs`-uMm+|?z~ literal 0 HcmV?d00001 diff --git a/public/logo512.png b/public/logo512.png new file mode 100644 index 0000000000000000000000000000000000000000..41427a2f0ee6dae7d1a19bde8b4699badc7022e9 GIT binary patch literal 11240 zcmc(FRa6{L(C^>`w-78i1PN}z-Gc;z1q%>@vx_gm-7P?H2*E<|;1U*H+%>pEa9?1N zyZ`$=-G}@9ozrJ$XR4}ey1V*U(i5evsf>?9g#!QpzN(6X4gjDc|Dpoe$X{TBG=>#< zLAR0BkOhF61l)TI4CFn%m5PoA0DM8x0z(1d4*4i>4*)!P0bu_l0EndnzzcA8%R31q z0o77nSpj&8NEn79@37oeH59S7urWzry%MT_AOHZ4I8_DN_mG979IuaLGo*dBUTI2l zB&aAPsLz7N3*jq;BCdHd zhG`Xiy1wsNku~~GGD1Zqy2WiTtu#;g)N}Tf7Q+H3xWML5pm!@sskr~*KC4hE%n2d< zJwFZYWSz*B=$!0?sOijAfvN}oltk{$vNz=EuUW^djd3k?1ijnT&mPv2a#M@MU8S8b zW~;zSiG$VeBznwkg8iQ8Y77Eie&|b`MaNMz{&^KEuXVX|{cj7m=VN|*8 zpM^1TY6r7jDC^GBk9f1om)b;fK@BmZea0|EKr)e7RXr9LPHK?bGJD^M@X@a3(!jr~ z9Pfmj@jJqm+okiBr>w{$w0k?z4$`#ZnC{`WeNtt*hQcu1lg85q#v8o(tKbs&6YFP# zRm(c6YKfNUWFGpQOIg)c-ilvbC-AdxNhK46UP)tj^b~a5PJ8``ocZ~7As^jcVcDcM zzueSF52qV$%(~}074@4(lrd|Q7H)VTuU!R46&nL*9!11x?BYMH)o=j(kEY9FiYM+S zG2XWwHIskJxjmbBH5llhVx9l-%HK6=adPE6LOxR`xyy_zvRn$Fp{j`6IkF_@lht_b zWAi#C9WrwYudR>(>Sp|XVT*rsAlH7@LoW$&dizZ8;B3Rc&}2?Ce3fOXrTJnTOKyyI zY*kJv{iLQWB89L5jq|2V#(cN)36FL^KYB4j65ga`-qy@g1D+#tB;MkBv{A-XS+`*A z)4N0W{Vc-zS%4^d%ztn(|J+-mwUBZbCI7U8^zV62g&>galg)Q}UCd4)=ac26ZdkoK zK{L5r!4HITls)%3?Ph%3#rb@TO?I=T?W#Fe3j@HE?#YeR3?_7u0b++MZst0pTD9!} z5l4mkS2!$HNk{wnQbM3HT(Y?`qJkSZ$28eJl6hm{mwmbtd4SbQ;u?@rk0Dd4_jw-i zPuGghM6?EkfayuUPJg&6>=@83*33gZ40?3>#G5uf&nWMcc2qMoBl#EB)CM)ZWbJ7| z?YRC^+mxH|OuTJ7;u&3Ixn4VjVb1Y6;O;FMomx3tw|M&Z0B-90HJS=*m&&S*XqO;> z_glCAbAVQtahxU*e6TiV?pd*U!u>DStlzlYHOnH#%Op~6!B5Ie2jx*Jd%^khzF9dt z@GESM`MzjHy3J90iof#Q!17wr0iIp|@Bwu?xJ2Eddkp=e?#@(>B=!nD&}q(rVibC@ zd#U++nZ69{1KlYIXvKaL32FF2yTlnkGOMiaoj!vu(=G!Z%sacC5H(#H2(gG8ZM_Y3 zS}!d&B(C|zAR*e3Kd``Nmr(l+I5o%pwV#xm>uEC-*>cMZUnQ{ic@1R~dBN_gK?<=Z zMue9!^Msc(0im!y*%dAPrwWj$0Q2@A@DvdZal&qE;hf{z@1B%DAFju#^m;Q`($PMU8F)nW_Yq3BH?nB| zwoOVL-z#9_*mJ*JzxaR$el6|q$K~*A%n-8nEcrM7iu)67C=)iftyF61ok*@o-c~dk z23maQa$Z~2t9$HVLb-%j=P;@ZdG-}yrj3bRUS7mD3p*BZJUwJ$y}eEPX^M{R(@}!# zV*;UyIuDV@(|Y?U6SlKpJA*^@vmy1<28sk<$?LA=yl5Bn&V>E^-%36;cL-tM~Yp|N30Mx z&W9o%U%g|0YK_2HXTqqMimi*2X?wJ`$@<6rP?G&Byw$s)OJZeTimFkZ|$NDb61U}1dWL&|Sf+w#JKl|7s*8~azbA&zOhe=9t@9kca)?SVohpt6%+=JepUP zC^-2r_&=v-!X@MeqUP2-SPSOcipMcmMv=hEZV)_VbY2+8k1u4oZbX=2#i!18 zAzHaXI-3c&!6)f4V0fRSW5tR=BIm-uWPIQhd8yZvx#P4qB&2qp>u91k9g=;$j9gs0zlP5s9!M1_*flUNN_ar( z8U?4{Nx|?}hx_&#ExRH=Su0Scx9!{Tg`$E{l=%d6muCVHsnnwmEPp~?z4WHG$D#Ej z>{Rqu-JgM|<+m1^+=Q-k412SU`$(H?rRv{^$>14ESUJPRyHNYDgB^L^5sf+gE=Rx7xX;xkMdwM6AMZU< zB)rAS6VF*`8@8NEBurM6iEfK>DfQ8h{Tq*cJlSvW3hPtaMFyDkQZEjd7$}gE;&AVG zO$hS=jZ_oXQ6a;@A;XGdCZdvttTm3RI$SH?wd1ixhBr(@Y6B?arh^LJ#eyJ#qRr`j zFUkd&$+$U{0nM@h?p)H(HGmBw({&KJ-?R93;Egas!;({k7|-C5Ev4H>R6tCA4 zr+L-6*gq1SSVrD!3+8%%u>P9GAp*1&)dj!N4sFbstOiBWp9`#{M}I$ax4m<4FQ(IT z2Jn)>s@Lydip#WOQZPbK|81}Nct)^7+bE-=@d0)^p!+GsH~NffaY23kSPLqGCA(>7 z@U&Zgk!Xqbu_;u3t()WLV|m%_gH;oPZnz573+j}!{g>%oDT?+b9->0QW6Oz!)YJn# z$^5RncV_M1adRD+o;~2px{g+@^6wnWDHQ|zIN)AhqY2?L6VTrbjg~|EK2Cfc)2tKT zn7U!hIm%a5qDP*~U52*$&%W&SFjuX9KFWAZ4oA{CC5TCJB1NPkX){X#Q7W}0+cJ3J z%2Qc141gC0{6)l5voR{!V;Iij3}=X>hU_?p$w~Fu1%QQGo?%Ag3t@gQFmroSSyqRl z|3dU?r1B3&v<{1xh^yBI<)}KF(xQ0sn}6}R&!G z#|+2pAM~`q6D6Pj#AqOww; zOqa$0)(sIm7humXz!qSjz^JFReT`O+#T*e^E;^YEg)p(jWfsIi-F3yb@ zEBzB-I~qAAe|tFXR>wyu^g)2&%YcA4-UwR!>0Qor1n?$ zPnQMh&|1AoJwOm=(9O~gGd53COuVu5jnvV?f2SX`%-={!{>ra^LX0Nr+WQSs?X>HW}On2hV%0mNVa8KhI)r~|7xfn_QC=qvqx{?0aZYqv# z%w*ri;}XXy`&|A2$4!Jvf{qP#R&YLEt<{?-6lCc2M3KAq1b*kygg82=fDm{+ZSxTC zAH)^~}G7I9ZP)hiONA-9{KMpOS-<>>E{kLv%S$otQBf8M>GvT?;WUL3qQ?p%Iy zH+p#!zF4_Kc=`b?yn3K0<)1%wAAR^y&9^G-g0j;iQ?j^Mz6g6`{DQp8hYaf!_EJa` zVVUIKKRNOS75L~|ytrMSxHU21#X(%+o%|ai?2E*|wnJj`nKpm5(u$YnUR&p&GtLQy z#oW8=y`UeK|2K!=XsMch6Mn1ulFKfxczTN(X--!o>vMB0=K{p`_=VJ-`UV@5Pv+^F zYX{^hA=oTXIonOD3m?v=el259r8i3{mzUGqYU1!AISYL$NMdg>Pba8N&^m{$CTp=1 z+LZZQmsm=HNA+=bM5k&@VZU~?G2F19sMG6EF;po&pbcvdVtv(G{tGuwFs%P%bt(4pqljbi^u)LrLSmNs!+T2Up zW*WWO)#lxhi4!L2@zN{Irn*6}BvF1+!2!Z}o$iOp?aSPRPtTSpL{Q!}?FM>hGO3i| zvBl9m*=;xqv!1(_N=Q)trJqxymm02NSE4pZQHmd>IO^$D>3MX|jM9k>g`+_@+Ao*NqyRUK0mlXe{t;)5Dtl@$}t1sz}D4D;Vy|!cmaQ&SqK>}{D|iXbgRDM<$e)y-%@-pf<5`G zek*{QDkrLpu&oKn?}#AXj?>} zg8@F{60zK^SSd>uaA};p=X5aIWNR+Df2G(?Cg%6EG*W5yoFjh-8<-!~e~4Uv?>gCd zTH5&fW$Lt@RVr44m9`c8F}bpPnXa}*$Yi6eg7<)X=^-KDXT~v?vWYh^kn-MUDZ7v;UjF#-uW(Uk zIjI+f=WL_BsVq7PE-#ox=v3H*Nn}5yR+Gwa{!4gg&*-X=Y$D9?(A#(WgBG-^_M;S{ z8EVngmdDADC%chVT_SF>$$k^3Y#6Rk0s3}8TNiPoVnyZVSt0l#a#!IWV(6A{jG<)h z?-d)BRwo=6X(qklsgiT1QR?@)iGYps&uR`)chtVU@v}bn?B#7HR7#l9LFvh}AOCx%COLsZBpNmbx1S;kN1 z_-Uq8Qi*!5jFgy4bO*7g6>8mI0~lo`!jThGDf-{K)HF$PzzaT>2vZ|9S|qD8xS#bV z-W2Di7~6)skkKrrG=f+~9mNqE96k$9s90AIf2-Nwf@02Kh9_Ra{c#*PZ&jU4tL9cpCcU! zTM;XFEcfTZZYasqUz^AOc+8brmZHm_IxA6-(|n0wqZ*sV#sPH~)wCCL$$yS|I+Zm4 zZ`G1GH@fFntQpkGSQg;Re6*RM;$M&1Rp&z4=DVTvu7gHeVOXmvgH$-Ef_N zO|q)I%5Zt+?hBu@t!4>#FwbbmnsFq1I;+K=;p7Swm#1(&geDUs!;?*x`ZW^s6xPvj zYF+v`njFuVr#7`v25#}52$zZ7ynvr&4M;bEa5pjyV{3~OfpX(6ghFUY17xZ<#CzMi z>}qd#kD(X)d3Ky*P{Oe)zxLl!!CkG~a-=q!M;YUiwr4{d3EHX|D*AKtO)Wf6Nezt1 zWr{RMBCPMbmVwnAQ{pz9ik@`B-81Bt$QDMz*^wl*(=EuE$yQ>nJ!TwM4})V5B_c9} za#^P$U2e(x7wad%f4Qabx^0S}?P2467meh|xSVT{f2)%*R8D~BR{NgW@QD&MrxsG= zDw5lZjEiDcjk^{7TYljZF}EkQm!X)4w^p1-pZXL@oRH4e^SGE0m#znph!5i9t&Tk&)*)3r8Nh-z*_ zp9lQ%uinnFL-i~h*?3H0dRU92!N_~JyMCO2dkn0GZUs7FGaXJRk(oWqkG2ukNgz~c z!r>7^&5r@y3nOP#bi+gQen4x`Xf~OZ|Cv85FSSlro`_16obn51{v@_ieul}xyfh-UM=c8(B@tnXoCrFZ{ECzxpwW+JjH3R^0>k`hS3HajyD) z3jThPKOT!+9>3@|GVVm2Gbr+I8PxO!hUJ{1yjlPb^EwYo7|BZ9?(fH%BCJa!WY{u_ z+V>}mvkB57uprA!DmW92(h=#=h;+83qzk@5ud(~FzR*KLVd@KKa!-~f|M-YuC?1}( zj=d`9rh6ooiHNgEe&Azn4?yBxS_M*=9Z%qz4T?leQ`=+Z2}p}y6RtmBhUc9?s3aRT zmJ+weon>gYz{N&8$v^Cl$jQE`dfebH@uNd9Xy|pjy1=)wa9MIbw7>()8zn?4;$#>Z z7qqzJb+QQxw4@hZo8?e)&R~PfxCC_9#BV-`cR#>)-UpYpWiMhev97 z<&Z#gNaY+1YM9F7Qtq$vaQuxayXlQn^0@021Q!|5ayqj$u zj{N4W2F4A)0{4vJ9dnUq+>Bm&*koVrGhg3pic}@AFvIz6to6JKfl|%Hx2&MaK2iqg zY$btQQBtf1_6v-LO}cXFB$&joW#E+bk)pOb#J|Ex13jwhY{KgemDVkFt0u-cVDK8Yh0xRG)w|ZdpV$y1O1PN1TMQSy~pt$pp?{ zuAaK|xsM+kc`l;VU$wkIEW2rB_n+=vPU_S5%Yv3irl7QSTT{>Ixc0#Deiy887-`X@ z%GSP;iK0QK(Q8~0_I(<|M%u?wQZFRn2yGXycFl*_OjqOE)uQaD6Vn(40`LR39{wP~<4#M?c7q0)qBurX`5IbZO-{kn z6{A1%R|6_im(S#oF^Y!D;ZDO1iTSPI$6WJ-b*GIi8C3dh6>0RSlOYZ4F51fkg6PDB zJ@V?;ekRF{aUjbtKp{=v-sV4n9mb`Hohis*5uUDkt^Bjq(zoeUKxs)hJy|om7>Vq9 zPW6y4l~!}Ch0+D~3hU?2IzUBS98Y#LYO+W4Y|PoY&3pq2$@!Rp_>KdjuKlP6?2R#9 zo{_bMX9qh-BwuG3Y_cc&51TCDM~h+n=3@aaUuYcVe|?5L3ED&^W+6xmQ@}a2F)FX~ z0d7&gL-|(-b1e+m0Qn7{!m6%gJ!wn(G;Vfo%C}|!MJ3i<_wvcaE)g>Pb#;_s2(vp} zHVm%5y!6HqFhbIu-*Vw=RS&QFNJ|_EZf||m>isk1{Pya@Wow($aQG#_`#ti0$>&gU zZ^P%aEpc!2D$Gx0>U25!Z`EVW^#4#>j+DkB;f#)Q!!lZ*KOJD5Ht>m0qIN(Ck@=8A z+DmX;$zzu-9ZSn9%!+R6TD`q3ZaBUWkRiTpc3;4mgKUsx^5KTeBQi6P8d0911Tvlv zEizE7^v;1jET7?)wK417(@gn>S)<SZO{aGnwF!LQ8*1sDslLKXA_jDSaL1FKa6n z_8Uux6T`?dF^%Tkd~dJx774%;{GsE*;b^}ql(S9X`a6ynG>$hjXYTv7Qj#d9%rI;g z>8lR7BRJd4k7dg)v>`(UFsEyoQTmhtVJuN}856J%dK8EYSqy>EzPFPbqygW?Ns>H( zSM+z}8i2^v1>#(D2jk6FWiVXYRNnyOxUuG0BKVKTLRMpHb0Q0{;pL75nEhYe5a7Q8 z^wq7Z@3!_jhYzpa;ADvPMjW6r|Bz38^TH!_r=#_zSouD<8mk_g+kpjdH$_Jp$Uvhf zmfuR7=zSr-8MV|m6^r+c7p0J+QFRH5l2}KF%;y@G=8#d$-s*?b7q_ZK;VHA3Sjb{q zVy84pqAxa*UVJ%C4bB*giK}?dnoHcxq|lYP(Rv{);AMs(Gx#o)l`8YAxvBg(#F8wt zhNfYvP{la-Iitx?R2oX+7gVG?>_i>u+K?_i?DK0?8}|CQ1s~3YbYjPMPG+#MB=7s01o@l)qGx0=8{0=)z2GGSd+)Ez;=eM29iFZbx}U~^530!YtUvEx#g*NP_>HwKTO-X9cTzl4 z30!zQ;pQi8mNJmrZAB(5;;1UGurod9unO8(crLqDA}vmnKaTez`?IR?t+VcX6kI_Q zF%Ytd9TxxI_8S>BLdMPV& zLb)X4m@0>#8;o-fjQO%ZAc13e9P(@KL0Ar6G70mB5`%PW2BuI85^Ux_Z6kXae{8P{ zDvsB4N!bnEY(4nVd2G-G(?#XVnECi*5wp)NqTpiNMwOpna}(>j?+G0@Q^PUDw3zW; zjE<5I$y;ZXW>U*xsI+ZeNq#dwpMZQE=_iSvns&CbG{}K8^UB8ee_|}!?I$xc=4W8q z-jarq+BT5_4QR|yFYk+H1x6j`XKs#(C8iJ)aBPooh?TU7YiWo$K7=|Z)M+N{zlzwo zm6ONMHiZEJ&2wTE$3Txmz$0~+@n>5ucU50~G93xVu3G!!1g?63vcVvD z&ZFTDb>v>vsPBvXO>=M*XrYuLw+$;;b;Yb?J2zArU%%wZ>F~O9Ilwa=6#+ptQ!T*% zT?Crwp3XdFhWh#H!}E}NIr~jp6lU`1KN{FO49V607&b0bW8y8&!UNU_pOnfG#Tll zd_H?OAuc?IYDTs9Z=+5OAsR=9Hlz4c++DFgoJOtk*l>P)V?eWBCvrDQ-_3L#}*5LL| zZZdq>UFApXxB-Vm5!fcD{pFreAy%bi=#3w>>j_hx{^V?L|z z7f<_I)y#hG>%Fb;%Fl~rwm5a!J}5c|{P#@HK~GPLnt+7q2drcNzHiipbCmo_v=rvj zd6bqiy45oxuRd;9#*66puM6S*Lpi-K`2vQE3mU(w&1&P@=#Ldv)K2(tsOFg)@Zm!d z)I`xq#ph{i8+GR;q5O0vH%M`8GMlx={Fjkck&{kL8SDIXca71?>+zu z6;7yWHwz-@)0F%YqQ7r8sjBtzN6Va_Qf(O5qjxVIOlN!$$r$V?M1N@iJFx;`)Qu*t z{~gd{GENn+HvM_^bKbe@B%fkbOG^v4<_Fd3ApogCk>51(ZoW6ZrcrH2egYL`>X6p| z%EjnAmv-@^vaWEpFQDaf9}&rJe+c?YT@FObPC|qwBd#6=#+A**>s%gpO{ope;O@0! z>oN56tuMGtua?csxmSE&OAu7LkM{h9m+xHU1wnuw%z~@4OLGDcZz4v4)a`BD6r%B= z!F}|JHJ*z9djPck0TZ82a{VBTQ^Zl6jEXj?T={m(hSf!neTBPQ@inl~;3=1KBX)(~ zeGQ|Y_&9F!k(Xj3CpYQJaD)>DyBf@@>nPSCd z{0DQmpl-!!NN*OBV3}Bg!MI#OC&xk+lP|s87uT3Ith@uLNJ>u2F-muW2A$lT=ZN`M zGRjvTJxOkOfXUJL(}pFL`c!BH{ChPp=3id?`7c)19LjfT>6UbBwB>eHqBgXgj3~3k zehv=Pm{TuckH;_Q`&mkin@=ch%4cS&rnuDUmgfvi0G19#@dNsr%Ht3@uw5;|N)kav|99b8@8h(W`Sed) zo_*o!#8jmD7HzGCNmpYJgIx{#b-1VeMQnwp>A~N9nYS3p4jR=_TDxAfVj5o6B>Zr( zt6`2kcvd6j=rYx4wO#VQ?h&oQ&6r4PRcL;-h4A5hklVw*SEAVjy)W~0PMnP3oG&{I zuG)|%rq*PV$F{4JdsuVt+W>`FTmz)Gn`QN4pqy*fq(;o-&DJyW3 z;LoFB^`qk+1|y!@G+utoiJ6tZxX-T1KbqH#6dtX+^zVkknv5BOUiwz#7hM?#u5HaZ z`;Moo6ef4oMRHQ3iIa`V$4Ch=y!j%8cjIYnNcOWvLv3qh`2uy{TkPwFUKH$aYiEgW zfT;T`4%MBMk8fjJynK(QSFWO4#-p{4=35c7CsJQVs}NO^QPJweap+d|zSEmSh>)Fx z$LdOuKh|AqBO`i*uUV0OBjVHLrJ^*3lQ?+)K9$;wR?_=^Z#@LjSd}Z@9j4KTFlDT8hHWudHH#{c;9gG3cu$Q6%+Wcaq{wu@$#mxO8Nai z0#2Y$cAvff{{sJl!#j}z24CJAy6aeY(SuzD|4-*7SB@cPjvZWN)71VY}$F zu?=bs4XbYJ0BB6O+*Y`xOr+|`WN4)H3W0*%pU{|U-_sAxPxto>_t5lU4F#%vSK|iu XUl6;W%L%0-RRF4rnhKS2AA|o7lzflw literal 0 HcmV?d00001 diff --git a/public/manifest.json b/public/manifest.json new file mode 100644 index 0000000..45d2f2a --- /dev/null +++ b/public/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "SDP", + "name": "Stellar Disbursement Platform", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/public/resources/disbursement-template.csv b/public/resources/disbursement-template.csv new file mode 100644 index 0000000..cbabd97 --- /dev/null +++ b/public/resources/disbursement-template.csv @@ -0,0 +1 @@ +phone,id,amount,verification diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..e9e57dc --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..7e340da --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,289 @@ +import { useEffect } from "react"; +import { BrowserRouter, Routes as RouterRoutes, Route } from "react-router-dom"; +import { Provider } from "react-redux"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import GitInfo from "generated/gitInfo"; + +import { store } from "store"; +import { Routes } from "constants/settings"; +import { PrivateRoute } from "components/PrivateRoute"; +import { InnerPage } from "components/InnerPage"; +import { UserSession } from "components/UserSession"; + +import { SignIn } from "pages/SignIn"; +import { MFAuth } from "pages/MFAuth"; +import { ForgotPassword } from "pages/ForgotPassword"; +import { ResetPassword } from "pages/ResetPassword"; +import { Home } from "pages/Home"; +import { Disbursements } from "pages/Disbursements"; +import { DisbursementDetails } from "pages/DisbursementDetails"; +import { DisbursementsNew } from "pages/DisbursementsNew"; +import { DisbursementDraftDetails } from "pages/DisbursementDraftDetails"; +import { DisbursementsDrafts } from "pages/DisbursementsDrafts"; +import { Receivers } from "pages/Receivers"; +import { ReceiverDetails } from "pages/ReceiverDetails"; +import { PaymentDetails } from "pages/PaymentDetails"; +import { Payments } from "pages/Payments"; +import { Wallets } from "pages/Wallets"; +import { Analytics } from "pages/Analytics"; +import { Profile } from "pages/Profile"; +import { Settings } from "pages/Settings"; +import { Help } from "pages/Help"; +import { NotFound } from "pages/NotFound"; +import { Unauthorized } from "pages/Unauthorized"; +import { SigninOidc } from "pages/Redirect"; + +import "styles.scss"; +// TODO: update favicons + +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + refetchOnWindowFocus: false, + retry: false, + }, + }, +}); + +export const App = () => { + useEffect(() => { + // Git commit hash + console.log("current commit hash: ", GitInfo.commitHash); + }, []); + + return ( + + + + + + {/* Sign in */} + + + + } + /> + {/* Forgot password */} + + + + } + /> + {/* Reset password */} + + + + } + /> + {/* 2FA Verification */} + + + + } + /> + {/* Home */} + + + + + + } + /> + {/* Disbursements */} + + + + + + } + /> + + + + + + } + /> + + + + + + } + /> + + + + + + } + /> + + + + + + } + /> + {/* Receivers */} + + + + + + } + /> + + + + + + } + /> + {/* Payments */} + + + + + + } + /> + + + + + + } + /> + {/* Wallets */} + + + + + + } + /> + {/* Analytics */} + + + + + + } + /> + {/* Profile */} + + + + + + } + /> + {/* Settings */} + + + + + + } + /> + {/* Help */} + + + + + + } + /> + {/* Unauthorized */} + + + + + + } + /> + {/* 404 */} + + + + + + } + /> + } /> + + + + + ); +}; diff --git a/src/api/authLogin.ts b/src/api/authLogin.ts new file mode 100644 index 0000000..f3dfd5c --- /dev/null +++ b/src/api/authLogin.ts @@ -0,0 +1,29 @@ +import { API_URL } from "constants/settings"; + +export const authLogin = async ( + email: string, + password: string, + recaptchaToken: string, + headers: Record, +): Promise => { + const response = await fetch(`${API_URL}/login`, { + method: "POST", + headers: { + "Content-Type": "application/json", + ...headers, + }, + body: JSON.stringify({ + email, + password, + recaptcha_token: recaptchaToken, + }), + }); + + const responseJson = await response.json(); + + if (responseJson.error) { + throw responseJson; + } + + return responseJson; +}; diff --git a/src/api/authRefreshToken.ts b/src/api/authRefreshToken.ts new file mode 100644 index 0000000..7899674 --- /dev/null +++ b/src/api/authRefreshToken.ts @@ -0,0 +1,19 @@ +import { API_URL } from "constants/settings"; + +export const authRefreshToken = async (token: string): Promise => { + const response = await fetch(`${API_URL}/refresh-token`, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + + const responseJson = await response.json(); + + if (responseJson.token) { + return responseJson.token; + } + + throw responseJson; +}; diff --git a/src/api/deleteAsset.ts b/src/api/deleteAsset.ts new file mode 100644 index 0000000..c9c01d3 --- /dev/null +++ b/src/api/deleteAsset.ts @@ -0,0 +1,18 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; +import { ApiAsset } from "types"; + +export const deleteAsset = async ( + token: string, + assetId: string, +): Promise => { + const response = await fetch(`${API_URL}/assets/${assetId}`, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + + return handleApiResponse(response); +}; diff --git a/src/api/getAssets.ts b/src/api/getAssets.ts new file mode 100644 index 0000000..b225953 --- /dev/null +++ b/src/api/getAssets.ts @@ -0,0 +1,15 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; +import { ApiAsset } from "types"; + +export const getAssets = async (token: string): Promise => { + const response = await fetch(`${API_URL}/assets`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + + return handleApiResponse(response); +}; diff --git a/src/api/getCountries.ts b/src/api/getCountries.ts new file mode 100644 index 0000000..835e0ae --- /dev/null +++ b/src/api/getCountries.ts @@ -0,0 +1,15 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; +import { ApiCountry } from "types"; + +export const getCountries = async (token: string): Promise => { + const response = await fetch(`${API_URL}/countries`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + + return handleApiResponse(response); +}; diff --git a/src/api/getDisbursementDetails.ts b/src/api/getDisbursementDetails.ts new file mode 100644 index 0000000..05cf232 --- /dev/null +++ b/src/api/getDisbursementDetails.ts @@ -0,0 +1,18 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; +import { ApiDisbursement } from "types"; + +export const getDisbursementDetails = async ( + token: string, + disbursementId: string, +): Promise => { + const response = await fetch(`${API_URL}/disbursements/${disbursementId}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + + return handleApiResponse(response); +}; diff --git a/src/api/getDisbursementDrafts.ts b/src/api/getDisbursementDrafts.ts new file mode 100644 index 0000000..4a46008 --- /dev/null +++ b/src/api/getDisbursementDrafts.ts @@ -0,0 +1,21 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL, UI_STATUS_DISBURSEMENT_DRAFT } from "constants/settings"; +import { ApiDisbursements } from "types"; + +export const getDisbursementDrafts = async ( + token: string, +): Promise => { + // TODO: Max page limit is 100. We will need to implement pagination for more + const response = await fetch( + `${API_URL}/disbursements?status=${UI_STATUS_DISBURSEMENT_DRAFT}&page_limit=100`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }, + ); + + return handleApiResponse(response); +}; diff --git a/src/api/getDisbursementInstructions.ts b/src/api/getDisbursementInstructions.ts new file mode 100644 index 0000000..e4c3bd0 --- /dev/null +++ b/src/api/getDisbursementInstructions.ts @@ -0,0 +1,22 @@ +import { API_URL, SESSION_EXPIRED } from "constants/settings"; + +export const getDisbursementInstructions = async ( + token: string, + disbursementId: string, +): Promise => { + const response = await fetch( + `${API_URL}/disbursements/${disbursementId}/instructions`, + { + method: "GET", + headers: { + Authorization: `Bearer ${token}`, + }, + }, + ); + + if (response.status === 401) { + throw SESSION_EXPIRED; + } + + return await response.blob(); +}; diff --git a/src/api/getDisbursementReceivers.ts b/src/api/getDisbursementReceivers.ts new file mode 100644 index 0000000..49a7c9d --- /dev/null +++ b/src/api/getDisbursementReceivers.ts @@ -0,0 +1,25 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { handleSearchParams } from "api/handleSearchParams"; +import { API_URL } from "constants/settings"; +import { ApiDisbursementReceivers, PaginationParams } from "types"; + +export const getDisbursementReceivers = async ( + token: string, + disbursementId: string, + searchParams?: PaginationParams, +): Promise => { + const params = handleSearchParams(searchParams); + + const response = await fetch( + `${API_URL}/disbursements/${disbursementId}/receivers${params}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }, + ); + + return handleApiResponse(response); +}; diff --git a/src/api/getDisbursements.ts b/src/api/getDisbursements.ts new file mode 100644 index 0000000..f59396a --- /dev/null +++ b/src/api/getDisbursements.ts @@ -0,0 +1,29 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { handleSearchParams } from "api/handleSearchParams"; +import { API_URL, UI_STATUS_DISBURSEMENT } from "constants/settings"; +import { ApiDisbursements, PaymentsSearchParams } from "types"; + +export const getDisbursements = async ( + token: string, + searchParams?: PaymentsSearchParams, +): Promise => { + // ALL status is for UI only + if (searchParams?.status === "ALL") { + delete searchParams.status; + } + + const params = handleSearchParams({ + status: UI_STATUS_DISBURSEMENT, + ...searchParams, + }); + + const response = await fetch(`${API_URL}/disbursements${params}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + + return handleApiResponse(response); +}; diff --git a/src/api/getOrgInfo.ts b/src/api/getOrgInfo.ts new file mode 100644 index 0000000..761fb2b --- /dev/null +++ b/src/api/getOrgInfo.ts @@ -0,0 +1,15 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; +import { ApiOrgInfo } from "types"; + +export const getOrgInfo = async (token: string): Promise => { + const response = await fetch(`${API_URL}/organization`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + + return handleApiResponse(response); +}; diff --git a/src/api/getOrgLogo.ts b/src/api/getOrgLogo.ts new file mode 100644 index 0000000..78ddd56 --- /dev/null +++ b/src/api/getOrgLogo.ts @@ -0,0 +1,8 @@ +import { API_URL } from "constants/settings"; + +export async function getOrgLogo(): Promise { + const response = await fetch(`${API_URL}/organization/logo`); + + const responseBlob = await response.blob(); + return URL.createObjectURL(responseBlob); +}; diff --git a/src/api/getPaymentDetails.ts b/src/api/getPaymentDetails.ts new file mode 100644 index 0000000..84e42f7 --- /dev/null +++ b/src/api/getPaymentDetails.ts @@ -0,0 +1,18 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; +import { ApiPayment } from "types"; + +export const getPaymentDetails = async ( + token: string, + paymentId: string, +): Promise => { + const response = await fetch(`${API_URL}/payments/${paymentId}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + + return handleApiResponse(response); +}; diff --git a/src/api/getPayments.ts b/src/api/getPayments.ts new file mode 100644 index 0000000..b257be2 --- /dev/null +++ b/src/api/getPayments.ts @@ -0,0 +1,26 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { handleSearchParams } from "api/handleSearchParams"; +import { API_URL } from "constants/settings"; +import { ApiPayments, PaymentsSearchParams } from "types"; + +export const getPayments = async ( + token: string, + searchParams?: PaymentsSearchParams, +): Promise => { + // ALL status is for UI only + if (searchParams?.status === "ALL") { + delete searchParams.status; + } + + const params = handleSearchParams(searchParams); + + const response = await fetch(`${API_URL}/payments${params}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + + return handleApiResponse(response); +}; diff --git a/src/api/getProfileInfo.ts b/src/api/getProfileInfo.ts new file mode 100644 index 0000000..700faae --- /dev/null +++ b/src/api/getProfileInfo.ts @@ -0,0 +1,17 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; +import { ApiProfileInfo } from "types"; + +export const getProfileInfo = async ( + token: string, +): Promise => { + const response = await fetch(`${API_URL}/profile`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + + return handleApiResponse(response); +}; diff --git a/src/api/getReceiverDetails.ts b/src/api/getReceiverDetails.ts new file mode 100644 index 0000000..8df40ff --- /dev/null +++ b/src/api/getReceiverDetails.ts @@ -0,0 +1,18 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; +import { ApiReceiver } from "types"; + +export const getReceiverDetails = async ( + token: string, + receiverId: string, +): Promise => { + const response = await fetch(`${API_URL}/receivers/${receiverId}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + + return handleApiResponse(response); +}; diff --git a/src/api/getReceivers.ts b/src/api/getReceivers.ts new file mode 100644 index 0000000..cf3a4f0 --- /dev/null +++ b/src/api/getReceivers.ts @@ -0,0 +1,26 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { handleSearchParams } from "api/handleSearchParams"; +import { API_URL } from "constants/settings"; +import { ApiReceivers, ReceiversSearchParams } from "types"; + +export const getReceivers = async ( + token: string, + searchParams?: ReceiversSearchParams, +): Promise => { + // ALL status is for UI only + if (searchParams?.status === "ALL") { + delete searchParams.status; + } + + const params = handleSearchParams(searchParams); + + const response = await fetch(`${API_URL}/receivers${params}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + + return handleApiResponse(response); +}; diff --git a/src/api/getStatistics.ts b/src/api/getStatistics.ts new file mode 100644 index 0000000..55f2e85 --- /dev/null +++ b/src/api/getStatistics.ts @@ -0,0 +1,15 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; +import { ApiStatistics } from "types"; + +export const getStatistics = async (token: string): Promise => { + const response = await fetch(`${API_URL}/statistics`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + + return handleApiResponse(response); +}; diff --git a/src/api/getStellarAccountInfo.ts b/src/api/getStellarAccountInfo.ts new file mode 100644 index 0000000..512725c --- /dev/null +++ b/src/api/getStellarAccountInfo.ts @@ -0,0 +1,17 @@ +import { HORIZON_URL } from "constants/settings"; +import { shortenAccountKey } from "helpers/shortenAccountKey"; +import { ApiStellarAccount } from "types"; + +export const getStellarAccountInfo = async ( + stellarAddress: string, +): Promise => { + const response = await fetch(`${HORIZON_URL}/accounts/${stellarAddress}`, { + method: "GET", + }); + + if (response.status === 404) { + throw `${shortenAccountKey(stellarAddress)} address was not found.`; + } + + return await response.json(); +}; diff --git a/src/api/getStellarAccountPayments.ts b/src/api/getStellarAccountPayments.ts new file mode 100644 index 0000000..545e91a --- /dev/null +++ b/src/api/getStellarAccountPayments.ts @@ -0,0 +1,32 @@ +import { HORIZON_URL } from "constants/settings"; +import { shortenAccountKey } from "helpers/shortenAccountKey"; +import { ApiStellarOperationRecord, ApiStellarPaymentType } from "types"; + +export const getStellarAccountPayments = async ( + stellarAddress: string, +): Promise => { + // TODO: make params dynamic + const response = await fetch( + `${HORIZON_URL}/accounts/${stellarAddress}/operations?limit=20&order=desc`, + { + method: "GET", + }, + ); + + if (response.status === 404) { + throw `${shortenAccountKey(stellarAddress)} address was not found.`; + } + + const ACCEPTED_TYPE: ApiStellarPaymentType[] = [ + "payment", + "path_payment_strict_send", + "path_payment_strict_receive", + ]; + + const responseJson = await response.json(); + const { records } = responseJson._embedded; + + return records.filter((r: ApiStellarOperationRecord) => + ACCEPTED_TYPE.includes(r.type), + ); +}; diff --git a/src/api/getStellarTransaction.ts b/src/api/getStellarTransaction.ts new file mode 100644 index 0000000..87f3df7 --- /dev/null +++ b/src/api/getStellarTransaction.ts @@ -0,0 +1,20 @@ +import { HORIZON_URL } from "constants/settings"; +import { shortenString } from "helpers/shortenString"; +import { ApiStellarTransaction } from "types"; + +export const getStellarTransaction = async ( + transactionHash: string, +): Promise => { + const response = await fetch( + `${HORIZON_URL}/transactions/${transactionHash}`, + { + method: "GET", + }, + ); + + if (response.status === 404) { + throw `${shortenString(transactionHash, 10)} transaction was not found.`; + } + + return await response.json(); +}; diff --git a/src/api/getUsers.ts b/src/api/getUsers.ts new file mode 100644 index 0000000..02e389c --- /dev/null +++ b/src/api/getUsers.ts @@ -0,0 +1,15 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; +import { ApiUser } from "types"; + +export const getUsers = async (token: string): Promise => { + const response = await fetch(`${API_URL}/users`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + + return handleApiResponse(response); +}; diff --git a/src/api/getWallets.ts b/src/api/getWallets.ts new file mode 100644 index 0000000..ddd34b4 --- /dev/null +++ b/src/api/getWallets.ts @@ -0,0 +1,15 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; +import { ApiWallet } from "types"; + +export const getWallets = async (token: string): Promise => { + const response = await fetch(`${API_URL}/wallets`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + + return handleApiResponse(response); +}; diff --git a/src/api/handleApiErrorString.ts b/src/api/handleApiErrorString.ts new file mode 100644 index 0000000..e445ccd --- /dev/null +++ b/src/api/handleApiErrorString.ts @@ -0,0 +1,14 @@ +import { GENERIC_ERROR_MESSAGE } from "constants/settings"; +import { ApiError } from "types"; + +export const handleApiErrorString = (error: ApiError): string => { + // Make sure error is not an empty object + if (JSON.stringify(error) === "{}") { + return GENERIC_ERROR_MESSAGE; + } + + return (error?.extras?.message || + error.error || + error || + GENERIC_ERROR_MESSAGE) as string; +}; diff --git a/src/api/handleApiResponse.ts b/src/api/handleApiResponse.ts new file mode 100644 index 0000000..8d661f8 --- /dev/null +++ b/src/api/handleApiResponse.ts @@ -0,0 +1,16 @@ +import { SESSION_EXPIRED } from "constants/settings"; +import { ApiError } from "types"; + +export const handleApiResponse = async (response: Response) => { + if (response.status === 401) { + throw SESSION_EXPIRED; + } + + const responseJson = await response.json(); + + if (responseJson.error) { + throw responseJson as ApiError; + } + + return responseJson; +}; diff --git a/src/api/handleSearchParams.ts b/src/api/handleSearchParams.ts new file mode 100644 index 0000000..302fc15 --- /dev/null +++ b/src/api/handleSearchParams.ts @@ -0,0 +1,17 @@ +import { createUrlSearchParamsString } from "helpers/createUrlSearchParamsString"; +import { sanitizeObject } from "helpers/sanitizeObject"; + +export const handleSearchParams = (searchParams: T) => { + let params = ""; + + if (searchParams) { + // Remove params with empty strings + const sanitizedParams = sanitizeObject(searchParams); + + if (Object.keys(sanitizedParams).length > 0) { + params = createUrlSearchParamsString(sanitizedParams); + } + } + + return params; +}; diff --git a/src/api/mfAuth.ts b/src/api/mfAuth.ts new file mode 100644 index 0000000..0450b36 --- /dev/null +++ b/src/api/mfAuth.ts @@ -0,0 +1,25 @@ +import { API_URL } from "constants/settings"; + +export const mfAuth = async ( + mfaCode: string, + rememberMe: boolean, + recaptchaToken: string, + headers: Record, +): Promise => { + const response = await fetch(`${API_URL}/mfa`, { + method: "POST", + headers: { + "Content-Type": "application/json", + ...headers, + }, + body: JSON.stringify({ + mfa_code: mfaCode, + remember_me: rememberMe, + recaptcha_token: recaptchaToken, + }), + }); + + const responseJson = await response.json(); + + return responseJson; +}; diff --git a/src/api/patchDisbursementStatus.ts b/src/api/patchDisbursementStatus.ts new file mode 100644 index 0000000..1a17ee9 --- /dev/null +++ b/src/api/patchDisbursementStatus.ts @@ -0,0 +1,25 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; +import { DisbursementStatus } from "types"; + +export const patchDisbursementStatus = async ( + token: string, + disbursementId: string, + status: DisbursementStatus, +): Promise<{ message: string }> => { + const response = await fetch( + `${API_URL}/disbursements/${disbursementId}/status`, + { + method: "PATCH", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + status, + }), + }, + ); + + return handleApiResponse(response); +}; diff --git a/src/api/patchOrgInfo.ts b/src/api/patchOrgInfo.ts new file mode 100644 index 0000000..96f24fc --- /dev/null +++ b/src/api/patchOrgInfo.ts @@ -0,0 +1,50 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; +import { sanitizeObject } from "helpers/sanitizeObject"; +import { OrgUpdateInfo } from "types"; + +export const patchOrgInfo = async ( + token: string, + fields: OrgUpdateInfo, +): Promise<{ message: string }> => { + const fieldsToSubmit = sanitizeObject(fields); + + if (Object.keys(fieldsToSubmit).length === 0) { + throw Error( + "Update organization info requires at least one field to submit", + ); + } + + const formData = new FormData(); + + Object.entries(fieldsToSubmit).forEach(([key, value]) => { + switch (key) { + case "name": + formData.append("data", `{"organization_name": "${value}"}`); + break; + case "timezone": + formData.append("data", `{"timezone_utc_offset": "${value}"}`); + break; + case "logo": + formData.append("logo", value as Blob); + break; + default: + throw Error(`Update organization does not accept ${key} field`); + } + }); + + // BE always expects data object + if (!formData.get("data")) { + formData.append("data", "{}"); + } + + const response = await fetch(`${API_URL}/organization`, { + method: "PATCH", + headers: { + Authorization: `Bearer ${token}`, + }, + body: formData, + }); + + return handleApiResponse(response); +}; diff --git a/src/api/patchPaymentsRetry.ts b/src/api/patchPaymentsRetry.ts new file mode 100644 index 0000000..ada7769 --- /dev/null +++ b/src/api/patchPaymentsRetry.ts @@ -0,0 +1,20 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; + +export const patchPaymentsRetry = async ( + token: string, + paymentIds: string[], +): Promise<{ message: string }> => { + const response = await fetch(`${API_URL}/payments/retry`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + payment_ids: paymentIds, + }), + }); + + return handleApiResponse(response); +}; diff --git a/src/api/patchProfileInfo.ts b/src/api/patchProfileInfo.ts new file mode 100644 index 0000000..a5d9b16 --- /dev/null +++ b/src/api/patchProfileInfo.ts @@ -0,0 +1,32 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; +import { sanitizeObject } from "helpers/sanitizeObject"; + +export const patchProfileInfo = async ( + token: string, + fields: { + firstName?: string; + lastName?: string; + email?: string; + }, +): Promise<{ message: string }> => { + const fieldsToSubmit = sanitizeObject({ + first_name: fields.firstName, + last_name: fields.lastName, + email: fields.email, + }); + + if (Object.keys(fieldsToSubmit).length === 0) { + throw Error("Update profile info requires at least one field to submit"); + } + + const response = await fetch(`${API_URL}/profile`, { + method: "PATCH", + headers: { + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify(fieldsToSubmit), + }); + + return handleApiResponse(response); +}; diff --git a/src/api/patchUserRole.ts b/src/api/patchUserRole.ts new file mode 100644 index 0000000..5d6405e --- /dev/null +++ b/src/api/patchUserRole.ts @@ -0,0 +1,23 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; +import { UserRole } from "types"; + +export const patchUserRole = async ( + token: string, + userId: string, + role: UserRole, +): Promise<{ message: string }> => { + const response = await fetch(`${API_URL}/users/roles`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + user_id: userId, + roles: [role], + }), + }); + + return handleApiResponse(response); +}; diff --git a/src/api/patchUserStatus.ts b/src/api/patchUserStatus.ts new file mode 100644 index 0000000..b4e61ff --- /dev/null +++ b/src/api/patchUserStatus.ts @@ -0,0 +1,22 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; + +export const patchUserStatus = async ( + token: string, + userId: string, + isActive: boolean, +): Promise<{ message: string }> => { + const response = await fetch(`${API_URL}/users/activation`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + user_id: userId, + is_active: isActive, + }), + }); + + return handleApiResponse(response); +}; diff --git a/src/api/postAssets.ts b/src/api/postAssets.ts new file mode 100644 index 0000000..fbace86 --- /dev/null +++ b/src/api/postAssets.ts @@ -0,0 +1,25 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; +import { ApiAsset } from "types"; + +export const postAssets = async ( + token: string, + asset: { + code: string; + issuer: string; + }, +): Promise => { + const response = await fetch(`${API_URL}/assets`, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + code: asset.code, + issuer: asset.issuer, + }), + }); + + return handleApiResponse(response); +}; diff --git a/src/api/postDisbursement.ts b/src/api/postDisbursement.ts new file mode 100644 index 0000000..2085e6f --- /dev/null +++ b/src/api/postDisbursement.ts @@ -0,0 +1,24 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; +import { ApiDisbursement, Disbursement } from "types"; + +export const postDisbursement = async ( + token: string, + disbursement: Disbursement, +): Promise => { + const response = await fetch(`${API_URL}/disbursements`, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + name: disbursement.name, + wallet_id: disbursement.wallet.id, + asset_id: disbursement.asset.id, + country_code: disbursement.country.code, + }), + }); + + return handleApiResponse(response); +}; diff --git a/src/api/postDisbursementFile.ts b/src/api/postDisbursementFile.ts new file mode 100644 index 0000000..131649d --- /dev/null +++ b/src/api/postDisbursementFile.ts @@ -0,0 +1,24 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; + +export const postDisbursementFile = async ( + token: string, + disbursementId: string, + file: File, +) => { + const formData = new FormData(); + formData.append("file", file); + + const response = await fetch( + `${API_URL}/disbursements/${disbursementId}/instructions`, + { + method: "POST", + headers: { + Authorization: `Bearer ${token}`, + }, + body: formData, + }, + ); + + return handleApiResponse(response); +}; diff --git a/src/api/postForgotPassword.ts b/src/api/postForgotPassword.ts new file mode 100644 index 0000000..52c15e2 --- /dev/null +++ b/src/api/postForgotPassword.ts @@ -0,0 +1,20 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; + +export const postForgotPassword = async ( + email: string, + recaptchaToken: string, +): Promise<{ message: string }> => { + const response = await fetch(`${API_URL}/forgot-password`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + email, + recaptcha_token: recaptchaToken, + }), + }); + + return handleApiResponse(response); +}; diff --git a/src/api/postResetPassword.ts b/src/api/postResetPassword.ts new file mode 100644 index 0000000..8e0910b --- /dev/null +++ b/src/api/postResetPassword.ts @@ -0,0 +1,25 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; + +export const postResetPassword = async ( + password: string, + resetToken: string, +): Promise => { + const response = await fetch(`${API_URL}/reset-password`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + // TODO: decode password before sending when BE is ready + password, + reset_token: resetToken, + }), + }); + + if (response.status === 200) { + return true; + } else { + return handleApiResponse(response); + } +}; diff --git a/src/api/postUser.ts b/src/api/postUser.ts new file mode 100644 index 0000000..64a0419 --- /dev/null +++ b/src/api/postUser.ts @@ -0,0 +1,24 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; +import { ApiNewUser, NewUser } from "types"; + +export const postUser = async ( + token: string, + newUser: NewUser, +): Promise => { + const response = await fetch(`${API_URL}/users`, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + first_name: newUser.first_name, + last_name: newUser.last_name, + roles: [newUser.role], + email: newUser.email, + }), + }); + + return handleApiResponse(response); +}; diff --git a/src/assets/logo-euroc.png b/src/assets/logo-euroc.png new file mode 100644 index 0000000000000000000000000000000000000000..885423b7766e9cec4801c6efaf26f831b48c129a GIT binary patch literal 5103 zcmX9?2~>>V`=4nMMJ2RQCPMZ?X|cSm(zhszNSTOaE!s8aopwq}q|!1iNMC6p%U7y* zq6O_FB&K~;lV+OreeeCx@BE*0?!D)^=ibkKKF_)5bDn!|xbAmYpuAL>L?SJ4+-rAG zHZuO#=E}=@e(!BDi6ocr>g;YWb6sg7og%n2AL`}6rG-$t2+G`JSH(vn1YRM6<@x_} zmlnZg1<>r4bae)PC`{lHE;PsiviYM|pc5+Eo+ADKjoM7O^M-g`CO8@@u(~ce6d|;Y zmB;}1UlVRi!`&kUo*}bGLxnnp{{!?06WGOyU1`ESF=83irn`hmDsFjGVv`_ozbf2M zD*b+M!-PbfJrmh6w)ahZd!#U{-2h>MT$%t~o+p@f2Q%^i^#E%!^v5zE&6U3e`!S4IG-93EIUFqI5X}~?v-U?Xr z3k1F*BDKCb%kHRs@WK6VB*4*EPqo4*RvZ?S>w{2Ixtuoj-s(UXD}4@|$xKB9IqeLp z@l>k{eOz3O0pQAv(^k%6pn%H?H16T1%^{K0-#FS?yN7qzb!<_6uRlNTL{oz? zDQoMh3t68Zo^QNVBX`i8Bt&c;wx)Zs&(^5mua*ZFg!BbE+%?O|9jTw1)-w64J5)3p zzS{iGvzs&Zx*9ok@oSMAClo`Znh(iyK41Ioxb2L!)0NMPhV}Sq!_+$~@_b@{ocivU zf6V3pqeOU3bM^dPbM2k>MEiZ&$71q)qxO_$wauF6UF1c!(4RW2tIv)XQ%lnkml)T@ z^%S#?f&|MH8gZ+ zL^#BPtq^$i(X&>cyz+ur6nYPel zIB5(0Nr{DHo~+R5{p*-Vc0O*I>xz0><;)mX78=CnjbAGGX-RuksvwHPmw4L-#a4dB zN7Baaof9uE%WwCi^D}%XnhdSXDe5~t7&hNU4p>~8zaiQ12m}R#L>dwa$U*WBzxg6YWqeERh zl%>x!1M=#0BO`wa=@Qr@S}&s9@S)yQ>??a;$zDqTV^a5?Fe0enp95QIS4nP58T#`n z+FI;S$QkBcgQIP2YrKCoT28<-_pqIJq7Yj3#TgY7)V$(;*P}xH`{|qAD-S%GyK=Mr z0c&gTbswH~Yn7YUB_z)?t*^52R9)(pu+H<9icO(@lEeRkMG;ljIs zVe~)UyUdxC8BWqpbi-^){nj^LNtmKG7)RS3C?(P$r4jD)M@Zu==DZUAI!q-mUuvsj z*D7x6LGHq>LW;48N$jlrmD_tgl2S+yXFFX8?3Cyua3?NaKec8NSyCogqH*DfFDYLB zo0`Op*bGslVfqJgKodhQ4Xds`ASW~oJk*AYk=buzCpC7Xj%XKJLho%`h}MK`QVV}5 z#I$pc&ouolBC=Njv)2kI$wH&70tq=31YdvlBU1jK^FM*zZ0*{*v~wle$@c-(W7Z{4 zF?bP{88Z{LoPl4v79q_S&b=2s-zVZ+eSv494amnAh~IDQjdl&6gIm-yUpriwSj^)F ztEjU{hM9R=h)f=LNgh%KDcpJQo)#TJc*pK73HUp1^${Zv_4!$M4!YDJ<@6-a=)J4H zt)6X5S=>t=cxxNGDNioEXiYOELS%$Ht_R)HapW*Tcx>8 z`F^=WOjX?u)VUvarVC&y-O7t4O}&xBp3Rb z`WqTX2U7Sc8;B^ZA}FIN{!^7a-N0NkPVvGAL~9=?#>1lc#nPt8>7R}}&i1zXRh;PM z?$YhN1(s zE#bYQm}#vfM_o_k!e5-BC|nD!vZefKar{5nFJ(+>{F&vBb(5Cu<{?;c%F59k~k zp_r?GMeNi_^comQS3I$K#R%0jA4A`6xRv~G#VZN<-LfXrEXec~`@uU~p&N*jKI!UR z)8)cTz|CGI9A0$j`>zKjWDyc>>?QJC6pm-8x2~JR+Z47VsYXG3W@(1 zA&I|1h6MZl^od8q+QgZ7^-X=&td8@AJgco&J3FK*Q~ntp-mx8fxU0v%>b#5De3e^m z2okGXEu}dD&9s|Wmw!CM`5ig=vdNRXtfP)m}ift-pGBwP6A9PG4MvFeoOU|H-mRs`qHP{m40&i8}s(p>*I zkl2Vt(C}bpd@%h#jehw#Y}iR@W}2WMRz@-PXN}H&Y43L#b5Odj8tXoA^B=zL>iMH^ z{yez-2GW4^zK5UDJ>ja_LV3z`kY?BB&*pZC86Z*PRz3LAfaYzox-%qy0d5inxF_xt zd6besr-h2y_KgR(KG4={^PczZksZ2%U5fBZ!8@9|x~Mwf{FbefF9FrHod33TuNb*f zwP7(DnJ6|A@u5{Ql7qOS%lCv&k(dG(Z|!8wP0PAdFDU;&bq|yMBo)8_UgwT8=j*>i zZXi;wir`GxHQY>@&b+VVTYFCL`SV|}-ky zG(eFg(3*7H8D#94_0gtx0@Ux*PY4EA0O~e6fy|y+EHR?77fFkh`r&LK%-J;ub7@*> zKOUzL8Pq@+agpC|S2VYv8_|)Kx3?L7M4OSD*t8nac3PU9)PSEU$Nb%=n@(r#^EiEd z%g+EBqZ1SJ)W&?|XhqNu=Jb=iM#Tw$LKO3If<8!&X6NEJx?CV{=$>#mQ;ew(Cftdr-iJNB8fxX zBTztM(`y}wue#=ncw98aRJ84k=0Mu!RddegzywD*edYC)#IX-o~^VHed2|V5@sWuW8W(Jwt!6**zbLB=H-B|eB5ztQu>+?fqZ zsy^^qn}yH6?MDBSkK|}2t(f;_{eqC%r2~wbL5vACGsV0;#;OhhzR;NBn#UnkWvy;ew&vjm?IR?s2cf*um zsmmmCra4fgScvstm*MHZja0|=z`hu6tHq97IGmp9wBZvR&%M2G3ix^r69z)6CCY{q zH}N!jMIXw?l)OlJ2T^}yy4Y6XotMuHvfE@z;8Hgtm2YMC(|;p@z=3Qs)YfYN9}|E9q^@`MG4a>J>`JH2Fq~njrSs!FC60sOr0J^mRX;*`U({K zjZ~+Xs^7KsfVD_6jCdk0c4Lp=dLIx0sv#?tskOTO8VtctoSB|!dM$vSo9eJJ1}C_O zt6`|=naKt0w?y0aX>@BDlMygk47nHD*c9IZqbV(1qiSnXzvOFc|6Vka=!zbr>;%Y5O4xa-ka&PiVPCSDMU6f+GgJk}M2h1F?1#VA zT&@_dPE?>3;7mn0lCj{L(__Mj@4=zomjA8NsGJNw_JPLHHvcZ>2G)mbyVO3<7~RV! zR==ZEygZ2~i|MemB_+&u#jw$Q(p5;p4Z}LaS!g$0M!Y%K&!m=pSIcwb5ljK)*b!9I zpEuBU>%3V2cC=3F@(g|~O3=Ea6B*N3=OOidfndXG6!*p(MgpZ-BxFtGBHCbn&fu+5 zR4mc!X~Tmg2F0x|dBNkv+X*NF6B}|*1A9DBHu{p|=%c;x=XuaUN6_WcIG4S7 z&v|Cc)ceqt*0f?$pWQ|mI3cCz9;4ry{ICGjmRMwBqv$cvOX`hbAcWiuRT}UMxtXeD zl~Oj;kJJBPQf;zHpX^y$*Vd=Ppj5$`3D_6cs0!4H)*a1Eb|d}~n4Qo_6@BBojY=&H(V#`g}#iLPy~F*eq_z3i zn@D?2h8Oy9mgA53qmw7G8Hz5SP#kEJQjVb^(4LsMI8G6?eFqOFDf7vTJW8NAw-)xe z7=A$o?LbXX0XrqW(=Xv5U`i>?ungYj7lCu+Pekxpy;02Xff&nphDNu_is%kv$0Qmh zQGrDS11Nd2dv3J9pQ4VegT|m7E)GvXj!!?M)BH5c*=Vb1Wc6eCfD@3j<^@$w{U)O1 z%10`qIB3-kWL~+tRLKmk@gf{V=*Zo&p(#x9xRBL@P7oBap+a~A&Xc^=#urJQ7Q-0$ zr)x2hk&H$OI5s2!+)ny{D3fMUXHV#+Gz>wBdxvGd&(?tyvU;1^3n&n&6hJztJ~#bD zUxJ3-|9TRh`OPH%{+lvSpZ~rV{H#Zxy~LEO;Rv(cO~_d!0`D8CT&gR408iru5M7XW zq4b0B%y&ecGQB7rEk(*;-dPETDYk((fEb_b91nIbt>w!dj5N|>;^ zHAOv03H(a$4+85w7Bs*+Zk6ZcXP9Hf0wn>qZ6agSttx3)@j>2rayQ?sFGIva{X~Y- zX{4cZ8Bdc+rE0~e|K9()!{nT6)GW&;F8=GMt_y!7zjH`6laG?p-nYm;MMxw^`~7xh IHa^k+2b@3-UH||9 literal 0 HcmV?d00001 diff --git a/src/assets/logo-usdc.png b/src/assets/logo-usdc.png new file mode 100644 index 0000000000000000000000000000000000000000..460cc83d9742ade0b9f863c166cfee84d6e39768 GIT binary patch literal 5334 zcmV;{6e;V8P)Px}kV!;ARCr$PU3q*|)xH0o>?A=zKm-I?Ga-QhA(^4nS}E2A?W+`lBKnH>RHSw5 z%dp56WC>)Vpj6b*7A*<|w0$l`>w5}R!Aw}g5;9>CWfNs52?@!}eV;SQ&|xxj&$;)W zb7z8_fA2ZJ^?R0k&hPvV!Bt#R?aq4@LZ(3R^Z-aJ0I{6v)&a_Ckf{Ao>SntfgFfbL z*W{{^CMR(afm5E{)RDx*EC7@-Ch4wKWTW?Ir~Pi`{t=KH&Kx$4=p+d-` zO~s%Aa=z+v*d|1>>=6lov{CtTBLV0AR5fF9DP%j4E(dv?pYlE8jXU9J-hefZKA{#T>6ptPO{< zkniy)WIdvI6o9xp6ICV`{rjKl&P;&0HoN9mk}sqWh!vB(^d#6EYG(-E=x~o z07%Ixsw0F%%M$#DL|0K1cX`3U7#TWC0f5Esq^o=>0?RN$6QNn>a@cs|8Msvv4uETm zJ#O3UswjGKC=dX2SFhOAe^^}>yb2n*9M&jNyNAL65RRUIOG*nAK9YhcQm@9oZ>#W& z7k5i_@dv-}jh;6qdU+@c@aUgh_@exrRGz_ziy8@p0KiP=Q-S|EF$103Bm^~j>cnEH z&M3>b2Bm-aR1NOPFY$uHtReygh5=yKg0E##42ouEGHn|!0Qd_waMm`Qt*m3pDxiYl zg`pt;nDwi-cYzfRqde1QkpKYS^w4XP+|j6>kFj4w-2h0LSo}Isl*gDJF;IaH^*4tY z>O+x@6ae_-J9?%DL-I-tSb^PC0ePd`VSSigvvCbw0O&b+bGInB=YSrDJZ*krX@RAW zSa_;7suO7d@Cis4i=VsXEfz@(EMhs2KpV zoSzgQjjgi>@cKDuz4XbO;r7T~hDSval+MpKBxm-Ft+-I_Hbf&-W33?21OQ8pa}@|i zikAGLAGgEQU*4>n?3g8cvGvde-R<=>%PFCZt z{GGyOYoAmVyFPa?*MBHC0AvjP&fHA2NYr*_=CY~L~t>z?bU ziFI|Y2mPjs9?i(BE{BzQD~SUD;tzRt!QnHQ}vxH0P3${S67IV=(UGaa9gjI+~j2ZGp~L!4H=!1gUV2LtP1xn z5`UVgWp88s-m@6LO!IzDNSj6he@lTM(K80D6!^4|I6SrhVryZmGN= z;&1_g>i*|PEg00Z1&k{JICSK%%Dx=b8Q~IJqEB4*bo!?Yo-gzn=y>Cil z>U!)<4Spu*Br&=&xq0c5^hWEspa2ln`&%W&;7g7mj+#0T`aUQ6KRCF3BLM(ZvXZ%3 zi09Y``O&OxI3p&w#N%?<8jS+M0U+oa7t7c_7l|9{n4K!@Q-HsOX4@y&TA&dCEOzG- z0EVw^^Uifa?bkkow`pYM?#6%P9&eL{$ zd*pPD_mHMe^3gKYo9-6UT|-t8)lmXR0Vx2W!J9OQQ>~mhcL_h8E9YOI@|`=PD~4yc zW!aVa{lo32kh4-+@ROJSrWu*IK3UyfG{}?&n;I>u0I*DSo`hmN4!ZIK*Y}9CzCSJnQ^{Pw>s&Tr|9B; zX+tz^@A^T~Rxzbbx5(*Mxmpp$-+vUi3;vpgRky2!lF@Ip4~*oc4 z#lGn-Ao?RCvdR`Tlx!@%Pc7e%Pj;O)qFPwnvh*|Bu{?19f>NP6ueq8&@WpU&BV6NZk{$wp$a7o7lz?tRpEo=ijU5OMa@2w#0) zjk_J)#05G%%z#679r*B17jqqFLmyN>W zA85VG8aHxQ9KbpW$I+rek{BP2ZH%NDMyELG05B>b%c!4D>5GmWVdpG5U+y~x`(F>@ zbVV&phy-Ja!wqnw_HFV2;9U!FTfCtn-Q|1jvtwBNNqC=@YyO`f*b0Kj9VhB_=`X&@D{>W`n_?u{!jtFUysHUb2A;?2iXVe5XKRR5G7 zt;DZhGACihH2~;z<-#%Dad%&N4~?6V0hDKbb8Q6R00{48Ob$|4R9X1(5xoA{F|Exs z)xS0ZXfhYOGL0f?-y$9hMt4Q#&FVoHY-;kiny&$X#|r}L(0o1<@9Bi$R&BS5XpAF` zb(B@i006z5r#qltwt%t>%c8q|ZWfwxT;Ha2jLySqvPiaXo#DeER=&Tcd?Y)xZ)?0b zraKEO(g1KrpH_JJq0o7ijOG`tKMXQ>9L%~3R-#umyOBAMPXSmBMwQZcZH`fue> z$4(slzS@NT`Z^c zp1fIDh7T66S${u-m0x}*bOc}pgNXS15H>g5UFFIi=+53XFP1 zOxigXufcP7;P^SQscu+T(>5QxfQMc)a?|RHiy_5t0m>M?5T*ecG%!Q0h#Zo6=0_1d zgwnXNMI6>oRZsseS~nj3ZqF;hkux=VT}JPPuXg3zMtK*3A})urdWn7I0erCilzxE& zTHc=C3V-;G`rpT2KK~Z;KG1$K)SnegFHu1A=Xp=R)_CCo_5BCKpd+;%UHP}vUk;^3 zc5I*wL-9E0_W32CS-Z>0A0E)YwI!!8dDTH&stXbJ!U@#JQ-R5}j7)^dh>j08R4-)BM3kO1yG5d1t|$UgQc- z6US2E;w2CI3x4ixSXLY4jqGN`CYsxd1~L_Z0+|9@t%%?oG))|3YOy;{0>%;=_eSE}w@j^zq)zT7$kEmze)WX-}QIIAf z6^u`Y@k2V`8I?PLzIvjE|3+&7Z_msrDpUx0REvQE>$Ytki_fQrZxry!lbjF@x=r1y zgT7bqrmp!4?{5Cyh$*<*@^qL%v$o@OrNR3ML|Nj>ANX5;p`<++!IQsF=2Q^M@+@PE z=w)19Z>YqQhgPG{<)%$Co{Wm?!3ggdB*=%qQZ43CNPkOaSmcB_~KG z{wHJ7ChSReCsi1JkDd2&#`Jf-!kS|FLoEeFqyS)~tu3A(-j&&j==ljfM=@I5)z>HN zU);0No_NT21I-)-sB%LKcH!W6LLMqpwN)elpxX`2ur{X;mrsTCeg%rFz!r3a!IXz1 zSw{C+B6HdnR9*6L8Afj`1q@~n@hLJStrcDw z%lB;T&*tsGF^NyahZ6ui>EL}f`|X?i@TsAI&wry(HvrN`?1^)CsnB8ru2sSWrJRe_l5g-YA zhg|=5^!?!a+@$Q%R0A!8X_hmz6aMSA_H3mA?|Z>Cud%ZRJZmy z06_NzikE;Wh98rp8uMhr4z!F&qX_qK2!io31SRvdy;mqSqdFnWT=~{jnu zP`bdX+15kzcjDkl@%QjF3lgLOeG!~S6lpDKlZu6=rgJ4(qmfIvrfqHjP^D7s&J_wU zTC0Mg>g$;fe6)VGXg5kDB=cv=jm_}>@A)=%0&PL>OBgzT4oWg|9PvnXC2A756E4Pnaqd2j#LC>YJYJ|4^&vI0wZhkl<-x~wj0gUH`7pG?d^ z=QjHPHfajj0fGZgL-nF|9Ej1%D)wV=HZEs>b`G&_CXf^!0);MK#8Q-iz-4;Zy2n3Bmy97`ZiS5)amgLvyGxC?(%|x>Tl1hP|-aC_-Gn^Z-AxY z%MbOy9eu86RlEE>k^n%TtD!lPB$hgt!=^jIm+mz{ph7Yhg@HWQJeiI@osyWgj06DC zgDiTWCA;WZ^a-5;{E3+X0?O}iPp2cTV`w0R698uB5EkKlVIx325X2rDv3d`U^!@uY zjW45y0|56e+>Ns1<~>KlbI8N8pYOZjH9$C~gFv2R2Hk)zZJS~4d&XYU8d z{32EriA@W`!(UX-mj(bzSoXq@$52;c9m5O0U^Wpx0{EE7{6)M9ovW&n(O*3^;?e*> znToh&^h0xYpuP%}H_9CYAC_eYsQ{ot_nf@BTa?>lJg{As1tOU)sZDj|-=ZzGiAH^- z1HdPbS-*)I^^e%-Dt3MDU^#~dA>=h501bkq*o&4C5GkjL5_}_>Bze{4uuhQ7Bq;f? z0ia$Q@9tp*0DTwu!(lO@Je6vf!IY z(#0ki)?vMf0D!;TqHZPYu!RXth{xryN{OG)D}2NOfGW~u?7D>bHi=atl2qt5jL>!p zl<2DD>q?iTN8BhEkpQ@2M6f%T01$F3NvKmfh#3jh;vg@iO2h-;3NTD`o`hm7kD(B& zsS`Qna@g1jj7<=PheeYDfKQ=@MPnfV(>6@hjj6mFuQdD3&Vs&j?zHoGQfHke34lOd z8{Ruu2w;RxJ7{h8wo>PwRK9S~QLPOlt^QR3fKW!Y*f-q;C3-rD(gPqgvXnP^wiZy% oKq31HL0*}|_F<$sPLw?V51H4o*?rS*)Bpeg07*qoM6N<$f?)3-NdN!< literal 0 HcmV?d00001 diff --git a/src/assets/logo-xlm.png b/src/assets/logo-xlm.png new file mode 100644 index 0000000000000000000000000000000000000000..b6e9fa47fbbecac47adc82ec85da81d851ba605f GIT binary patch literal 2505 zcmV;)2{!hLP)C0002tP)t-s|Ns90 z008{_{QCO(Mn*>X`1lPC4Hgy_K|w(r92{0wR`m4r-rnB!_V(%N=`1WPBqSv4?CkLH z@XpT8*x1;?!NKzK^5f&lqj(9m03TToC?=jZ2mcz886HMF#}dwY9ybaZiXaY;!@qN1XOg@s>VU!|p`l$4ak z#l?w#eLV&xF<9D z{|`!X0!9i)x;;srtXHvbEnQW&t2^*{Uihav5R|xVGud?V z6G>;8_EMz&l@3IPpEOxI`A}%KIpi~ODp0v6@bl$EA&De~O*#K)rIf54vEeCx!X%M} znef!7@S@gZNnCu9YeIy z&u?)R$gRe3dCvZ>DJrkmM6ssxYF#rc4e-gp&A^4^<;dSgSPIlOAo|;h#mnKHP6)E2 zeDB|E#6u|u?O2Zdg|HML%10@*#Vb}TPux#avA+HdkzK2Km_*uwOeXOaNU4|fO{E!} z%lTAXsmNATsAA^*NYcqC6iDqF^dER;%2Tm5#_>uS0;r`dm{9qozaisufAFh4g+lrh zgfGpjVfZiGC1U(bH}-#<6rZWzd9?zXN8z+8BDRb2<%*x~Td8O2x4H&3;!A%oBj?}o zs=73Hh$rAnuzh6P`xf%wi<@iybq?|~@WTOU*X_NIQGZv=)oliT_=Vk&1GTZ|VYzWP zzS?hKw{L29hUNR@@mRY^oL}RAz_mYBI>6@n<~bCe39b|bZjKp$qP%%yLGRk@xU`wS zda&={SO;1xz-_ zAS~hm{Ch7OhG*IqgcnqsWP$hlyV%4fU>Dh4=A!eAI|GG|8K2m~$^ZC!<`Z~Z0*SZyC`RBXgXA4K=?H}-U{l&X zWsBAnx(7vzCqRwY98wHo9b<>4hlNO?i;VJHxs zN7{P0pxFSPJ}q02Z#cs@Dg4pE{Kbd$uHOPy2nv|~CR@~Q;7j(mbU5~7SA=|{HXLWe zu_p~(xIJWaOauiCzYfjCD}1>!2pg7dcp`Lu%K*bNc5rqCziCx`ifcTffWWUw7QmYk zcyZ4`K0Nh@l|TW^5M-PolMcg=jmXY#t;THFdae=>QV;^XO_<>gP|mZLp&o%>Zj*qJ zR_ZtKH=EGKNkd2A&99*BY$s*t{Mxb)r3RkXu9MfPxyHW1Yn0nCRRRoeG=9G?$`ggi&!b01yU7wtM6|G_fA z&JlWH1EQyybs4g)yw(fD)6$}z`?S|PW4{iWvG&)uG_Z@Tr~)K=vmO&Bq}i^Od%$3o zz>`W0yzG6WK{+3lC}_Ra4%2bE(3|BSF`bMNY-I5FIO;rn+Y}pTHNra*cobSVM&u z%|4hwRX0z;6H1T$(>Hj;Kgs*;7w|G`3Z6nBho8GSsH%udxR)^3WIJ}`DFjj`Q1y1_ z1|KO{TH&Atj>+3oDZV@FiPfn-lm_4L)KS-q!E*7E~`p z1qP!TgwK_x((kNT*Tp~wh~84Bh42s+Z~!y~$dQ(dz;ABSqyJrTWFh*H$vA-wJ^;>& zq(EV=6(huYMZ(ftF}1qt=q*`p>5l)D3&@+BOJFO|nQQW$-gNgdTeZ>ej%<7M$zwLV zL?v()kVZ4{e$d2^OA<>iV1$mM0Nb63sn0v4L88Nx22Uk$WfXIll_{T5pLBwG2BPF* zGd9B;T>PU}&frnu@r4q#Bl+lAFL~4eXaCzmQ2J`Yk)7zn<_^g%Ryy@R9#<2xvbRrf zjpl$UeECvf2F=FX$u { + if (accountInfo?.balances?.length === 0) { + return
There are no balances on this account
; + } + + return ( + <> + {accountInfo?.balances.map((b) => ( + + ))} + + ); +}; diff --git a/src/components/AssetAmount/index.tsx b/src/components/AssetAmount/index.tsx new file mode 100644 index 0000000..7f7cb8b --- /dev/null +++ b/src/components/AssetAmount/index.tsx @@ -0,0 +1,54 @@ +import { decimal } from "helpers/formatIntlNumber"; +import UsdcLogoSrc from "assets/logo-usdc.png"; +import EurocLogoSrc from "assets/logo-euroc.png"; +import XlmLogoSrc from "assets/logo-xlm.png"; +import "./styles.scss"; + +interface AssetAmountProps { + amount?: string; + assetCode: string; + fallback?: string; + showIcon?: boolean; +} + +export const AssetAmount: React.FC = ({ + amount, + assetCode, + fallback, + showIcon, +}: AssetAmountProps) => { + if (!amount) { + return fallback ? <>{fallback} : null; + } + + const assets = [ + { + code: "USDC", + image: UsdcLogoSrc, + }, + { + code: "EUROC", + image: EurocLogoSrc, + }, + { + code: "XLM", + image: XlmLogoSrc, + }, + ]; + + const foundAsset = assets.find((a) => a.code === assetCode); + + return ( + + {decimal.format(Number(amount))} + {assetCode} + {showIcon ? ( + + {foundAsset ? ( + {`${foundAsset.code} + ) : null} + + ) : null} + + ); +}; diff --git a/src/components/AssetAmount/styles.scss b/src/components/AssetAmount/styles.scss new file mode 100644 index 0000000..ce447c6 --- /dev/null +++ b/src/components/AssetAmount/styles.scss @@ -0,0 +1,24 @@ +@use "./styles-utils.scss" as *; + +.AssetAmount { + display: inline-flex !important; + align-items: center; + gap: pxToRem(4px); + + &__icon { + display: block; + width: pxToRem(12px); + height: pxToRem(12px); + border-radius: pxToRem(6px); + background-color: var(--color-gray-30); + border: 1px solid var(--color-gray-30); + overflow: hidden; + flex-shrink: 0; + + img { + display: block; + width: 100%; + height: 100%; + } + } +} diff --git a/src/components/Breadcrumbs/index.tsx b/src/components/Breadcrumbs/index.tsx new file mode 100644 index 0000000..66900fa --- /dev/null +++ b/src/components/Breadcrumbs/index.tsx @@ -0,0 +1,34 @@ +import { Fragment } from "react"; +import { Icon } from "@stellar/design-system"; +import { Link } from "react-router-dom"; +import "./styles.scss"; + +type Breadcrumb = { + label: string; + route?: string; +}; + +export const Breadcrumbs = ({ steps }: { steps: Breadcrumb[] }) => ( + +); diff --git a/src/components/Breadcrumbs/styles.scss b/src/components/Breadcrumbs/styles.scss new file mode 100644 index 0000000..b2a844d --- /dev/null +++ b/src/components/Breadcrumbs/styles.scss @@ -0,0 +1,25 @@ +@use "./styles-utils.scss" as *; + +.Breadcrumbs { + --Link-font-size: pxToRem(14px); + --Link-line-height: pxToRem(22px); + + display: flex; + align-items: center; + gap: pxToRem(4px); + font-weight: var(--font-weight-medium); + margin-bottom: pxToRem(16px); + color: var(--color-gray-60); + + &__separator { + display: block; + width: pxToRem(14px); + height: pxToRem(14px); + + svg { + width: 100%; + height: 100%; + fill: currentColor; + } + } +} diff --git a/src/components/CopyWithIcon/index.tsx b/src/components/CopyWithIcon/index.tsx new file mode 100644 index 0000000..187d89a --- /dev/null +++ b/src/components/CopyWithIcon/index.tsx @@ -0,0 +1,36 @@ +import { CopyText, Icon } from "@stellar/design-system"; +import "./styles.scss"; + +interface CopyWithIconProps { + textToCopy: string; + doneLabel?: string; + children: React.ReactNode | string; + iconSizeRem: string; +} + +export const CopyWithIcon = ({ + textToCopy, + doneLabel = "Copied", + children, + iconSizeRem, +}: CopyWithIconProps) => { + const customStyle = { + width: `${iconSizeRem}rem`, + height: `${iconSizeRem}rem`, + } as React.CSSProperties; + + return ( + +
+ {children} +
+ +
+
+
+ ); +}; diff --git a/src/components/CopyWithIcon/styles.scss b/src/components/CopyWithIcon/styles.scss new file mode 100644 index 0000000..f53db22 --- /dev/null +++ b/src/components/CopyWithIcon/styles.scss @@ -0,0 +1,21 @@ +@use "./styles-utils.scss" as *; + +.CopyWithIcon { + --CopyWithIcon-icon-size: 0; + + display: inline-flex; + align-items: center; + gap: 0.4em; + + &__icon { + display: flex; + align-items: center; + + svg { + display: block; + width: 80%; + height: 80%; + fill: var(--color-gray-50); + } + } +} diff --git a/src/components/CsvPreview/index.tsx b/src/components/CsvPreview/index.tsx new file mode 100644 index 0000000..d129b80 --- /dev/null +++ b/src/components/CsvPreview/index.tsx @@ -0,0 +1,87 @@ +import { useEffect, useState } from "react"; +import { parse } from "papaparse"; + +import "./styles.scss"; + +interface CsvPreviewProps { + file: File | undefined; +} + +export const CsvPreview = ({ file }: CsvPreviewProps) => { + const [fileData, setFileData] = useState(); + const [errorMessage, setErrorMessage] = useState(); + + useEffect(() => { + if (file) { + parse(file, { + header: true, + skipEmptyLines: true, + complete: (results) => { + const { data } = results; + + if (data?.length === 0) { + setErrorMessage("The CSV file is empty."); + return; + } + + // TODO: handle errors + + setErrorMessage(undefined); + setFileData(data); + }, + error: (error) => { + // TODO: handle error + console.log(">>> error: ", error); + }, + }); + } + }, [file]); + + if (errorMessage) { + return
{errorMessage}
; + } + + if (!fileData || fileData.length === 0) { + return null; + } + + const dataCols = Object.keys(fileData?.[0]); + const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + return ( +
+ + + {/* Row with alphabet letters */} + + {/* Adding extra cell for index */} + + {dataCols.map((col, index) => ( + + ))} + + + + + {/* Row with column names */} + + {/* Adding extra cell for index */} + + {dataCols.map((col) => ( + + ))} + + {/* Data rows with index */} + {fileData.map((item, rowIndex) => ( + + + {Object.values(item).map((val, valIndex) => ( + + ))} + + ))} + +
{alphabet.charAt(index)}
1{col}
{rowIndex + 2}{`${val}`}
+
+ ); +}; diff --git a/src/components/CsvPreview/styles.scss b/src/components/CsvPreview/styles.scss new file mode 100644 index 0000000..9c3500b --- /dev/null +++ b/src/components/CsvPreview/styles.scss @@ -0,0 +1,38 @@ +@use "./styles-utils.scss" as *; + +.CsvPreview { + max-height: pxToRem(400px); + overflow: auto; + + table { + width: 100%; + border-collapse: collapse; + white-space: nowrap; + + th, + td { + font-size: pxToRem(8px); + line-height: 1; + color: var(--color-gray-90); + font-weight: var(--font-weight-regular); + padding: 0 pxToRem(8px); + border: 1px solid var(--color-gray-50); + box-sizing: border-box; + height: pxToRem(16px); + } + + th { + background-color: var(--color-gray-40); + } + + td { + background-color: var(--color-gray-00); + } + + th:first-child, + td:first-child { + padding-left: pxToRem(4px); + padding-right: pxToRem(4px); + } + } +} diff --git a/src/components/CsvUpload/index.tsx b/src/components/CsvUpload/index.tsx new file mode 100644 index 0000000..60f5c76 --- /dev/null +++ b/src/components/CsvUpload/index.tsx @@ -0,0 +1,45 @@ +import { useState } from "react"; +import { formatUploadedFileDisplayName } from "helpers/formatUploadedFileDisplayName"; +import { CsvUploadButton } from "components/CsvUploadButton"; +import { FileUpload } from "components/FileUpload"; +import "./styles.scss"; + +interface CsvUploadProps { + onChange: (file?: File) => void; + isDisabled?: boolean; + initFile?: File; +} + +export const CsvUpload = ({ + onChange, + initFile, + isDisabled, +}: CsvUploadProps) => { + const [file, setFile] = useState(initFile); + + const handleChange = (inputFile?: File) => { + setFile(inputFile); + onChange(inputFile); + }; + + return ( +
+ + } + /> +
+ ); +}; diff --git a/src/components/CsvUpload/styles.scss b/src/components/CsvUpload/styles.scss new file mode 100644 index 0000000..561004a --- /dev/null +++ b/src/components/CsvUpload/styles.scss @@ -0,0 +1,14 @@ +@use "./styles-utils.scss" as *; + +.CsvUpload { + margin-top: pxToRem(16px); + + .FileUpload { + height: pxToRem(120px); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: pxToRem(12px); + } +} diff --git a/src/components/CsvUploadButton/index.tsx b/src/components/CsvUploadButton/index.tsx new file mode 100644 index 0000000..8ef3e3b --- /dev/null +++ b/src/components/CsvUploadButton/index.tsx @@ -0,0 +1,72 @@ +import { Icon } from "@stellar/design-system"; +import "./styles.scss"; + +interface CsvUploadButtonProps { + variant: "primary" | "secondary" | "tertiary"; + size: "md" | "sm" | "xs"; + onChange?: (file?: File) => void; + label?: string; + isDisabled?: boolean; + showIcon?: boolean; + // in standalone mode it uses local handleChange method + isStandalone?: boolean; +} + +export const CsvUploadButton = ({ + variant, + size, + onChange, + label = "Upload CSV", + isDisabled = false, + showIcon, + isStandalone, +}: CsvUploadButtonProps) => { + const additionalClasses = [ + "Button", + `Button--${variant}`, + `Button--${size}`, + ].join(" "); + + const handleChange = (event: React.ChangeEvent) => { + if (isStandalone) { + event.preventDefault(); + const inputFile = event.target?.files?.[0]; + + if (onChange && inputFile) { + onChange(inputFile); + } + + // We need to clear previous file/value to make it work when the same file is + // selected again. Without clearing, the browser is caching the file so it + // won't change even if it's updated and selected again. + event.target.value = ""; + } else { + if (onChange) { + // This event is actually a File but it won't accept it as a type + onChange(event as any); + } + } + }; + + return ( +
+ + +
+ ); +}; diff --git a/src/components/CsvUploadButton/styles.scss b/src/components/CsvUploadButton/styles.scss new file mode 100644 index 0000000..0b5c8cf --- /dev/null +++ b/src/components/CsvUploadButton/styles.scss @@ -0,0 +1,29 @@ +@use "./styles-utils.scss" as *; + +.CsvUploadButton { + label { + cursor: pointer; + } + + &[aria-disabled="true"] { + label { + cursor: not-allowed; + + color: var(--Button-color-text-disabled); + background-color: var(--Button-color-background-disabled); + border-color: var(--Button-color-border-disabled); + } + } + + @media (hover: hover) { + &:hover { + &[aria-disabled="true"] { + label { + color: var(--Button-color-text-disabled); + background-color: var(--Button-color-background-disabled); + border-color: var(--Button-color-border-disabled); + } + } + } + } +} diff --git a/src/components/DashboardAnalytics.tsx b/src/components/DashboardAnalytics.tsx new file mode 100644 index 0000000..c22c5fc --- /dev/null +++ b/src/components/DashboardAnalytics.tsx @@ -0,0 +1,162 @@ +import { useEffect } from "react"; +import { useDispatch } from "react-redux"; +import { Card, Notification } from "@stellar/design-system"; +import { InfoTooltip } from "components/InfoTooltip"; +import { AssetAmount } from "components/AssetAmount"; + +import { percent } from "helpers/formatIntlNumber"; +import { renderNumberOrDash } from "helpers/renderNumberOrDash"; +import { useRedux } from "hooks/useRedux"; +import { + clearStatisticsAction, + getStatisticsAction, +} from "store/ducks/statistics"; +import { AppDispatch } from "store"; + +export const DashboardAnalytics = () => { + const { statistics, userAccount } = useRedux("statistics", "userAccount"); + const { stats } = statistics; + const dispatch: AppDispatch = useDispatch(); + + const apiErrorStats = statistics.status === "ERROR" && statistics.errorString; + + const calculateRate = () => { + if (stats?.paymentsSuccessfulCounts && stats?.paymentsTotalCount) { + return Number(stats.paymentsSuccessfulCounts / stats.paymentsTotalCount); + } + + return 0; + }; + + useEffect(() => { + if (userAccount.isAuthenticated) { + dispatch(getStatisticsAction()); + } + + return () => { + dispatch(clearStatisticsAction()); + }; + }, [dispatch, userAccount.isAuthenticated]); + + if (apiErrorStats) { + return ( + + {apiErrorStats} + + ); + } + + return ( +
+ {/* TODO: add disbursement volume chart */} + + +
+
+
+ + Successful payment rate + +
+ {/* TODO: add chart */} +
{`${percent.format( + calculateRate(), + )}`}
+
+ +
+
+
+ +
+ {renderNumberOrDash(stats?.paymentsSuccessfulCounts)} +
+
+ +
+ +
+ {renderNumberOrDash(stats?.paymentsFailedCount)} +
+
+ +
+ +
+ {renderNumberOrDash(stats?.paymentsRemainingCount)} +
+
+
+
+
+
+ + +
+
+
+
+
+ + Total disbursed + +
+
+ +
+
+ + Average amount + +
+
+
+ +
+ {stats?.assets.map((a) => ( +
+
+ +
+
+ +
+
+ ))} +
+
+ +
+
+
+
+ +
+ {renderNumberOrDash(stats?.individualsTotalCount)} +
+
+ +
+ +
+ {renderNumberOrDash(stats?.walletsTotalCount)} +
+
+
+
+
+
+
+
+ ); +}; diff --git a/src/components/DisbursementButtons/index.tsx b/src/components/DisbursementButtons/index.tsx new file mode 100644 index 0000000..8090705 --- /dev/null +++ b/src/components/DisbursementButtons/index.tsx @@ -0,0 +1,226 @@ +import { Button, Icon } from "@stellar/design-system"; +import { useNavigate } from "react-router-dom"; +import { Routes } from "constants/settings"; +import { DisbursementDraftAction, DisbursementStep } from "types"; +import "./styles.scss"; + +interface DisbursementButtonsPros { + variant: DisbursementStep; + onSaveDraft: () => void; + onDiscard?: () => void; + onGoBack: () => void; + onNewDisbursement?: () => void; + onGoToDrafts?: () => void; + clearDrafts?: () => void; + isReviewDisabled?: boolean; + isDraftDisabled?: boolean; + isSubmitDisabled?: boolean; + isDraftPending?: boolean; + actionType?: DisbursementDraftAction; +} + +export const DisbursementButtons = ({ + variant, + onSaveDraft, + onDiscard, + onGoBack, + onNewDisbursement, + onGoToDrafts, + clearDrafts, + isReviewDisabled, + isDraftDisabled, + isSubmitDisabled, + isDraftPending, + actionType, +}: DisbursementButtonsPros) => { + const navigate = useNavigate(); + + const isSavePending = isDraftPending && actionType === "save"; + const isSubmitPending = isDraftPending && actionType === "submit"; + + const handleGoToDisbursements = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + + if (clearDrafts) { + clearDrafts(); + } + + navigate(Routes.DISBURSEMENTS); + }; + + const handleGoToDrafts = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + + if (onGoToDrafts) { + onGoToDrafts(); + } else { + if (clearDrafts) { + clearDrafts(); + } + + navigate(Routes.DISBURSEMENT_DRAFTS); + } + }; + + const handleStartNewDisbursement = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + + if (onNewDisbursement) { + onNewDisbursement(); + } else { + if (clearDrafts) { + clearDrafts(); + } + + navigate(Routes.DISBURSEMENT_NEW); + } + }; + + const handleDiscard = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + if (onDiscard) { + onDiscard(); + } + }; + + const handleSaveDraft = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + onSaveDraft(); + }; + + const handleGoBack = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + onGoBack(); + }; + + const renderContent = () => { + if (variant === "edit") { + return ( + <> + + +
+ + +
+ + ); + } + + if (variant === "preview") { + return ( + <> + + +
+ + +
+ + ); + } + + // "confirmation" variant + return ( + <> + + +
+ + +
+ + ); + }; + + return
{renderContent()}
; +}; diff --git a/src/components/DisbursementButtons/styles.scss b/src/components/DisbursementButtons/styles.scss new file mode 100644 index 0000000..1c9d46e --- /dev/null +++ b/src/components/DisbursementButtons/styles.scss @@ -0,0 +1,14 @@ +@use "./styles-utils.scss" as *; + +.DisbursementButtons { + margin-top: pxToRem(8px); + display: flex; + align-items: center; + justify-content: space-between; + + &--continue { + display: flex; + align-items: center; + gap: pxToRem(8px); + } +} diff --git a/src/components/DisbursementDetails/index.tsx b/src/components/DisbursementDetails/index.tsx new file mode 100644 index 0000000..1db0bc2 --- /dev/null +++ b/src/components/DisbursementDetails/index.tsx @@ -0,0 +1,320 @@ +import { useEffect } from "react"; +import { + Card, + Input, + Select, + Title, + Notification, +} from "@stellar/design-system"; +import { useDispatch } from "react-redux"; + +import { AppDispatch } from "store"; +import { getCountriesAction } from "store/ducks/countries"; +import { getAssetsAction } from "store/ducks/assets"; +import { getWalletsAction } from "store/ducks/wallets"; + +import { InfoTooltip } from "components/InfoTooltip"; +import { formatUploadedFileDisplayName } from "helpers/formatUploadedFileDisplayName"; +import { useRedux } from "hooks/useRedux"; +import { + ApiAsset, + ApiCountry, + ApiWallet, + Disbursement, + DisbursementStep, +} from "types"; + +import "./styles.scss"; + +interface DisbursementDetailsProps { + variant: DisbursementStep; + details?: Disbursement; + csvFile?: File; + onChange?: (state: Disbursement) => void; + onValidate?: (isValid: boolean) => void; +} + +const initDetails: Disbursement = { + id: "", + name: "", + country: { + name: "", + code: "", + }, + asset: { + id: "", + code: "", + }, + wallet: { + id: "", + name: "", + }, + createdAt: "", + status: "DRAFT", +}; + +export const DisbursementDetails: React.FC = ({ + variant, + details = initDetails, + csvFile, + onChange, + onValidate, +}: DisbursementDetailsProps) => { + const { assets, countries, wallets } = useRedux( + "assets", + "countries", + "wallets", + ); + + enum FieldId { + NAME = "name", + COUNTRY_CODE = "country_code", + ASSET_CODE = "asset_code", + WALLET_ID = "wallet_id", + } + + const dispatch: AppDispatch = useDispatch(); + + // Don't fetch again if we already have them in store + useEffect(() => { + if (!countries.status) { + dispatch(getCountriesAction()); + } + + if (!assets.status) { + dispatch(getAssetsAction()); + } + + if (!wallets.status) { + dispatch(getWalletsAction()); + } + }, [assets.status, countries.status, wallets.status, dispatch]); + + const apiErrors = [ + assets.errorString, + countries.errorString, + wallets.errorString, + ]; + + const sanitizedApiErrors = apiErrors.filter((e) => Boolean(e)); + + const validateInputs = (inputs: Disbursement) => { + const missingFields = []; + + if (!inputs.name) { + missingFields.push(FieldId.NAME); + } else if (!inputs.country.code) { + missingFields.push(FieldId.COUNTRY_CODE); + } else if (!inputs.asset.code) { + missingFields.push(FieldId.ASSET_CODE); + } else if (!inputs.wallet.id) { + missingFields.push(FieldId.WALLET_ID); + } + + const isValid = missingFields.length === 0; + + if (onValidate) { + onValidate(isValid); + } + }; + + const updateState = (updatedDetail: T) => { + const updatedState = { + ...details, + ...updatedDetail, + }; + + // Updating parent state + if (onChange) { + onChange(updatedState); + } + + validateInputs(updatedState); + }; + + const updateDraftDetails = ( + event: React.ChangeEvent, + ) => { + const { id, value } = event.target; + + switch (id) { + case FieldId.COUNTRY_CODE: + // eslint-disable-next-line no-case-declarations + const country = countries.items.find( + (c: ApiCountry) => c.code === value, + ); + + updateState({ + country: { + name: country?.name || "", + code: country?.code || "", + }, + }); + + break; + case FieldId.ASSET_CODE: + // eslint-disable-next-line no-case-declarations + const asset = assets.items.find((a: ApiAsset) => a.id === value); + + updateState({ + asset: { + id: asset?.id || "", + code: asset?.code || "", + }, + }); + + break; + case FieldId.WALLET_ID: + // eslint-disable-next-line no-case-declarations + const wallet = wallets.items.find((w: ApiWallet) => w.id === value); + + updateState({ + wallet: { + id: wallet?.id || "", + name: wallet?.name || "", + }, + }); + + break; + case FieldId.NAME: + updateState({ + name: value, + }); + break; + default: + // do nothing + } + }; + + const renderDropdownDefault = (isLoading: boolean) => { + return ; + }; + + const renderContent = () => { + if (variant === "preview" || variant === "confirmation") { + return ( + <> +
+ +
+ {details.country.name} +
+
+ +
+ +
+ {details.asset.code} +
+
+ +
+ +
+ {details.wallet.name} +
+
+ +
+ +
+ {details.name} +
+
+ + {variant === "confirmation" ? ( +
+ +
+ {csvFile ? formatUploadedFileDisplayName(csvFile) : ""} +
+
+ ) : null} + + ); + } + + // "edit" variant by default + return ( + <> + + + + + + + + + ); + }; + + return ( + <> + {sanitizedApiErrors && sanitizedApiErrors.length > 0 ? ( + + {sanitizedApiErrors.map((e) => ( +
{e}
+ ))} +
+ ) : null} + + + + Disbursement details + + +
+ {renderContent()} +
+
+ + ); +}; diff --git a/src/components/DisbursementDetails/styles.scss b/src/components/DisbursementDetails/styles.scss new file mode 100644 index 0000000..f186abb --- /dev/null +++ b/src/components/DisbursementDetails/styles.scss @@ -0,0 +1,22 @@ +@use "./styles-utils.scss" as *; + +.DisbursementDetailsFields { + &__inputs { + margin-top: pxToRem(16px); + display: flex; + flex-wrap: wrap; + gap: pxToRem(24px); + + & > * { + flex: 1 1 45%; + } + } + + &__value { + font-size: pxToRem(12px); + line-height: pxToRem(20px); + color: var(--color-gray-80); + font-weight: var(--font-weight-medium); + margin-top: pxToRem(4px); + } +} diff --git a/src/components/DisbursementInstructions/index.tsx b/src/components/DisbursementInstructions/index.tsx new file mode 100644 index 0000000..0cfd1af --- /dev/null +++ b/src/components/DisbursementInstructions/index.tsx @@ -0,0 +1,98 @@ +import { Button, Card, Title } from "@stellar/design-system"; +import { formatUploadedFileDisplayName } from "helpers/formatUploadedFileDisplayName"; +import { saveFile } from "helpers/saveFile"; +import { CsvUpload } from "components/CsvUpload"; +import { CsvUploadButton } from "components/CsvUploadButton"; +import { CsvPreview } from "components/CsvPreview"; +import { InfoTooltip } from "components/InfoTooltip"; +import "./styles.scss"; + +interface DisbursementInstructionsProps { + variant: "upload" | "preview"; + csvFile?: File; + onChange: (file: File | undefined) => void; + isDisabled?: boolean; +} + +export const DisbursementInstructions: React.FC< + DisbursementInstructionsProps +> = ({ + variant, + csvFile, + onChange, + isDisabled, +}: DisbursementInstructionsProps) => { + const handleDownloadTemplate = async ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + saveFile({ + fileUrl: "/resources/disbursement-template.csv", + suggestedFileName: "disbursement-template.csv", + }); + }; + + const renderContent = () => { + if (variant === "upload") { + return ( + <> +
+ Please complete all fields above before uploading a disbursement + file +
+ + + + ); + } + + return ( + <> + {csvFile ? ( + <> +
{formatUploadedFileDisplayName(csvFile)}
+ + + ) : ( +
Please upload a disbursement file
+ )} + + ); + }; + + return ( + +
+ + Disbursement instructions + + +
+ + + {variant === "preview" ? ( + onChange(file)} + label={csvFile ? "Reupload CSV" : "Upload CSV"} + isStandalone={true} + /> + ) : null} +
+
+ + {renderContent()} +
+ ); +}; diff --git a/src/components/DisbursementInstructions/styles.scss b/src/components/DisbursementInstructions/styles.scss new file mode 100644 index 0000000..87b3a50 --- /dev/null +++ b/src/components/DisbursementInstructions/styles.scss @@ -0,0 +1,17 @@ +@use "./styles-utils.scss" as *; + +.DisbursementInstructions { + &__titleWrapper { + display: flex; + align-items: center; + justify-content: space-between; + gap: pxToRem(16px); + } + + &__buttons { + display: flex; + align-items: center; + justify-content: flex-end; + gap: pxToRem(8px); + } +} diff --git a/src/components/DisbursementsTable.tsx b/src/components/DisbursementsTable.tsx new file mode 100644 index 0000000..2c61192 --- /dev/null +++ b/src/components/DisbursementsTable.tsx @@ -0,0 +1,182 @@ +import { useNavigate } from "react-router-dom"; +import { Card, Link, Notification } from "@stellar/design-system"; +import { Routes } from "constants/settings"; +import { formatDateTime } from "helpers/formatIntlDateTime"; +import { renderNumberOrDash } from "helpers/renderNumberOrDash"; +import { useSort } from "hooks/useSort"; +import { Table } from "components/Table"; +import { AssetAmount } from "components/AssetAmount"; +import { + ActionStatus, + Disbursement, + DisbursementsSearchParams, + SortByDisbursements, + SortDirection, +} from "types"; + +interface DisbursementsTableProps { + disbursementItems: Disbursement[]; + searchParams: DisbursementsSearchParams | undefined; + apiError: string | boolean | undefined; + isFiltersSelected: boolean | undefined; + status: ActionStatus | undefined; + onSort?: (sort?: SortByDisbursements, direction?: SortDirection) => void; +} + +export const DisbursementsTable: React.FC = ({ + disbursementItems, + searchParams, + apiError, + isFiltersSelected, + status, + onSort, +}: DisbursementsTableProps) => { + const hasSort = Boolean(onSort); + const { sortBy, sortDir, handleSort } = useSort(onSort); + + const navigate = useNavigate(); + + const handleDisbursementClicked = ( + event: React.MouseEvent, + disbursement: Disbursement, + ) => { + event.preventDefault(); + + if (disbursement.status === "DRAFT") { + navigate(`${Routes.DISBURSEMENT_DRAFTS}/${disbursement.id}`); + } else { + navigate(`${Routes.DISBURSEMENTS}/${disbursement.id}`); + } + }; + + if (apiError) { + return ( + + {apiError} + + ); + } + + if (disbursementItems?.length === 0) { + if (status === "PENDING") { + return
Loading…
; + } + + if (searchParams?.q) { + if (isFiltersSelected) { + return ( +
+ {`There are no disbursements matching "${searchParams.q}" with selected filters`} +
+ ); + } + + return ( +
+ {`There are no disbursements matching "${searchParams.q}"`} +
+ ); + } + + if (isFiltersSelected) { + return ( +
+ There are no disbursements matching selected filters +
+ ); + } + + return
There are no disbursements
; + } + + const defaultSortDirection = hasSort ? "default" : undefined; + + return ( +
+ + + + {/* TODO: put back once ready */} + {/* + + */} + handleSort("name")} + > + Disbursement name + + Total payments + Successful + Failed + Remaining + handleSort("created_at")} + > + Created at + + + Total amount + + + Amount disbursed + + + + + {disbursementItems.map((d) => ( + + {/* TODO: put back once ready */} + {/* + + */} + + handleDisbursementClicked(event, d)} + > + {d.name} + + + + {renderNumberOrDash(d.stats?.paymentsTotalCount)} + + + {renderNumberOrDash(d.stats?.paymentsSuccessfulCount)} + + + {renderNumberOrDash(d.stats?.paymentsFailedCount)} + + + {renderNumberOrDash(d.stats?.paymentsRemainingCount)} + + + + {formatDateTime(d.createdAt)} + + + + + + + + + + + ))} + +
+
+
+ ); +}; diff --git a/src/components/DropdownMenu/index.tsx b/src/components/DropdownMenu/index.tsx new file mode 100644 index 0000000..b5ca8d2 --- /dev/null +++ b/src/components/DropdownMenu/index.tsx @@ -0,0 +1,72 @@ +import { Floater } from "@stellar/design-system"; +import { NavLink } from "react-router-dom"; +import "./styles.scss"; + +interface DropdownMenuProps { + triggerEl: JSX.Element; + children: JSX.Element | JSX.Element[]; +} + +interface DropdownMenuComponent { + Item: React.FC; +} + +export const DropdownMenu: React.FC & + DropdownMenuComponent = ({ triggerEl, children }: DropdownMenuProps) => { + return ( + +
{children}
+
+ ); +}; + +interface DropdownMenuItemProps + extends React.AnchorHTMLAttributes { + children: React.ReactNode; + to?: string; + isHighlight?: boolean; +} + +const DropdownMenuItem: React.FC = ({ + children, + to, + isHighlight, + ...props +}: DropdownMenuItemProps) => { + const handleNavLinkStyle = ({ isActive }: { isActive: boolean }) => { + return [ + "DropdownMenu__item", + isActive ? "DropdownMenu__item--current" : null, + ] + .filter(Boolean) + .join(" "); + }; + + // Route/nav links must have "to" prop + if (to) { + return ( + + {children} + + ); + } + + const styleClasses = [ + "DropdownMenu__item", + ...(isHighlight ? ["DropdownMenu__item--highlight"] : []), + ].join(" "); + + return ( + + {children} + + ); +}; + +DropdownMenu.displayName = "DropdownMenu"; +DropdownMenu.Item = DropdownMenuItem; diff --git a/src/components/DropdownMenu/styles.scss b/src/components/DropdownMenu/styles.scss new file mode 100644 index 0000000..f4d17bc --- /dev/null +++ b/src/components/DropdownMenu/styles.scss @@ -0,0 +1,50 @@ +@use "./styles-utils.scss" as *; + +.DropdownMenu { + display: flex; + flex-direction: column; + gap: pxToRem(4px); + padding: pxToRem(4px); + + &__item { + display: block; + width: pxToRem(168px); + padding: pxToRem(4px) pxToRem(8px); + border-radius: pxToRem(4px); + background-color: var(--color-gray-00); + text-decoration: none; + color: var(--color-gray-80); + font-size: pxToRem(14px); + line-height: pxToRem(22px); + font-weight: var(--font-weight-medium); + transition: all var(--anim-transition-default); + cursor: pointer; + + &--highlight { + color: var(--color-red-60); + + &[aria-disabled="true"] { + color: var(--color-red-50); + } + } + + @media (hover: hover) { + &:hover { + background-color: var(--color-gray-10); + + &[aria-disabled="true"] { + background-color: var(--color-gray-00); + } + } + } + + &--current { + background-color: var(--color-gray-10); + cursor: default; + } + + &[aria-disabled="true"] { + cursor: not-allowed; + } + } +} diff --git a/src/components/ExpandContent/index.tsx b/src/components/ExpandContent/index.tsx new file mode 100644 index 0000000..0e38ee5 --- /dev/null +++ b/src/components/ExpandContent/index.tsx @@ -0,0 +1,45 @@ +import { useState } from "react"; +import { Card, Icon, Title } from "@stellar/design-system"; +import "./styles.scss"; + +interface ExpandContentProps { + title: React.ReactElement | string; + children: React.ReactElement | string; +} + +export const ExpandContent: React.FC = ({ + title, + children, +}: ExpandContentProps) => { + const [isOpen, setIsOpen] = useState(false); + + return ( + +
+
{ + event.preventDefault(); + setIsOpen(!isOpen); + }} + > + {title} +
+ {isOpen ? : } +
+
+
+ {/* Extra div is needed to handle the top padding */} +
+
{children}
+
+
+
+
+ ); +}; diff --git a/src/components/ExpandContent/styles.scss b/src/components/ExpandContent/styles.scss new file mode 100644 index 0000000..9f4ca60 --- /dev/null +++ b/src/components/ExpandContent/styles.scss @@ -0,0 +1,46 @@ +@use "../../styles-utils.scss" as *; + +.ExpandContent { + &__heading { + cursor: pointer; + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: pxToRem(16px); + } + + &__icon { + width: pxToRem(20px); + height: pxToRem(20px); + flex-shrink: 0; + flex-grow: 0; + + svg { + display: block; + width: 100%; + height: 100%; + fill: currentColor; + } + } + + &__content { + display: grid; + grid-template-rows: 0fr; + transition: grid-template-rows ease-in-out 400ms; + font-size: pxToRem(14px); + line-height: pxToRem(22px); + color: var(--color-gray-70); + + &--open { + grid-template-rows: 1fr; + } + + & > div { + overflow: hidden; + + & > div { + padding-top: pxToRem(16px); + } + } + } +} diff --git a/src/components/FileUpload/index.tsx b/src/components/FileUpload/index.tsx new file mode 100644 index 0000000..7c35523 --- /dev/null +++ b/src/components/FileUpload/index.tsx @@ -0,0 +1,153 @@ +import { useState, useRef, useEffect, cloneElement } from "react"; +import "./styles.scss"; + +interface FileUploadProps { + uploadButton?: React.ReactElement; + onChange: (file?: File) => void; + acceptedType: string[]; + infoMessage: string; + disabled?: boolean; + extraInfo?: React.ReactElement; +} + +export const FileUpload = ({ + uploadButton, + onChange, + acceptedType, + infoMessage, + disabled, + extraInfo, +}: FileUploadProps) => { + const dropareaElRef = useRef(null); + + const [isDropInProgress, setIsDropInProgress] = useState(false); + const [isDropDisabled, setIsDropDisabled] = useState(false); + const [errorMessage, setErrorMessage] = useState(""); + + useEffect(() => { + const droparea = dropareaElRef?.current; + + const handleEnter = (event: Event) => { + event.preventDefault(); + + if (disabled) { + setIsDropDisabled(true); + } else { + setIsDropInProgress(true); + setErrorMessage(""); + } + }; + + const handleLeave = (event: Event) => { + if (disabled) { + setIsDropDisabled(false); + } else { + event.preventDefault(); + setIsDropInProgress(false); + } + }; + + const handleDrop = (event: DragEvent) => { + if (disabled) { + return; + } + + const files = event?.dataTransfer?.files; + const droppedFile = files?.[0]; + + // setFile(undefined); + onChange(undefined); + + if (files && files.length > 1) { + setErrorMessage("Too many files. Please upload only one file."); + return; + } + + if (droppedFile) { + if (!acceptedType.includes(droppedFile.type)) { + // We need to use only the second part of the type, for example "png" + // from "image/png" + const acceptedTypeString = acceptedType + .map((t) => { + const type = t.split("/")[1]; + return `.${type}`; + }) + .join(" or "); + + setErrorMessage( + `Wrong format. Please upload a ${acceptedTypeString} file.`, + ); + return; + } + + onChange(droppedFile); + setErrorMessage(""); + } + }; + + ["dragenter", "dragover"].forEach((evtName) => { + droparea?.addEventListener(evtName, handleEnter); + }); + + ["dragleave", "drop"].forEach((evtName) => { + droparea?.addEventListener(evtName, handleLeave); + }); + + droparea?.addEventListener("drop", handleDrop); + + return () => { + ["dragenter", "dragover"].forEach((evtName) => { + droparea?.removeEventListener(evtName, handleEnter); + }); + + ["dragleave", "drop"].forEach((evtName) => { + droparea?.removeEventListener(evtName, handleLeave); + }); + + droparea?.removeEventListener("drop", handleDrop); + }; + }, [acceptedType, disabled, onChange]); + + const handleChange = (event: React.ChangeEvent) => { + event.preventDefault(); + const inputFile = event.target?.files?.[0]; + + setErrorMessage(""); + onChange(inputFile); + + // We need to clear previous file/value to make it work when the same file is + // selected again. Without clearing, the browser is caching the file so it + // won't change even if it's updated and selected again. + event.target.value = ""; + }; + + const containerClasses = [ + "FileUpload", + ...(isDropInProgress ? ["FileUpload--active"] : []), + ...(isDropDisabled ? ["FileUpload--disabled"] : []), + ].join(" "); + + return ( +
+ {uploadButton ? ( +
+ {cloneElement(uploadButton, { + onChange: handleChange, + disabled: Boolean(disabled), + })} +
+ ) : null} + +
+ {extraInfo ? extraInfo : null} + {errorMessage ? ( +
+ {errorMessage} +
+ ) : ( +
{infoMessage}
+ )} +
+
+ ); +}; diff --git a/src/components/FileUpload/styles.scss b/src/components/FileUpload/styles.scss new file mode 100644 index 0000000..14befed --- /dev/null +++ b/src/components/FileUpload/styles.scss @@ -0,0 +1,35 @@ +@use "./styles-utils.scss" as *; + +.FileUpload { + background-color: var(--color-gray-10); + border: 1px solid var(--color-gray-30); + border-radius: pxToRem(4px); + padding: pxToRem(16px); + transition: border-color var(--anim-transition-default), + background-color var(--anim-transition-default); + + &--active { + background-color: var(--color-gray-20); + border: 1px dashed var(--color-gray-50); + } + + &--disabled { + background-color: var(--color-red-20); + border: 1px dashed var(--color-red-50); + } + + &__button { + flex-shrink: 0; + } + + &__message { + font-size: pxToRem(12px); + line-height: pxToRem(20px); + font-weight: var(--font-weight-regular); + color: var(--color-gray-60); + + &--error { + color: var(--color-red-60); + } + } +} diff --git a/src/components/FilterMenu/index.tsx b/src/components/FilterMenu/index.tsx new file mode 100644 index 0000000..7ffd8d9 --- /dev/null +++ b/src/components/FilterMenu/index.tsx @@ -0,0 +1,115 @@ +import { useCallback, useLayoutEffect, useRef, useState } from "react"; +import { Button, Icon, Floater } from "@stellar/design-system"; +import "./styles.scss"; + +interface FilterMenuProps { + children: JSX.Element | JSX.Element[]; + onSubmit: () => void; + onReset: () => void; + isSubmitDisabled: boolean; + isResetDisabled: boolean; +} + +export const FilterMenu: React.FC = ({ + children, + onSubmit, + onReset, + isSubmitDisabled, + isResetDisabled, +}: FilterMenuProps) => { + const [isOpen, setIsOpen] = useState(false); + const buttonRef = useRef(null); + const contentRef = useRef(null); + + const handleClickOutside = useCallback((event: MouseEvent) => { + const target = event.target as Node; + + if ( + contentRef?.current?.contains(target) || + buttonRef?.current?.contains(target) + ) { + return; + } + + setIsOpen(false); + }, []); + + useLayoutEffect(() => { + if (isOpen) { + document.addEventListener("pointerup", handleClickOutside); + } else { + document.removeEventListener("pointerup", handleClickOutside); + } + + return () => { + document.removeEventListener("pointerup", handleClickOutside); + }; + }, [isOpen, handleClickOutside]); + + const toggleOpen = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + setIsOpen(!isOpen); + }; + + const handleSubmit = (event: React.FormEvent) => { + event.preventDefault(); + setIsOpen(false); + onSubmit(); + }; + + const handleReset = (event: React.FormEvent) => { + event.preventDefault(); + setIsOpen(false); + onReset(); + }; + + return ( + + + + } + placement="bottom" + isVisible={isOpen} + isContrast={false} + > +
+
{children}
+ +
+ + +
+
+
+ ); +}; diff --git a/src/components/FilterMenu/styles.scss b/src/components/FilterMenu/styles.scss new file mode 100644 index 0000000..2c40936 --- /dev/null +++ b/src/components/FilterMenu/styles.scss @@ -0,0 +1,30 @@ +@use "./styles-utils.scss" as *; + +.FilterMenu { + width: pxToRem(308px); + padding: pxToRem(24px); + + &__inputs { + display: flex; + flex-direction: column; + gap: pxToRem(24px); + } + + &__item { + .Label { + color: var(--color-gray-80); + } + } + + &__buttons { + display: flex; + align-items: center; + justify-content: space-between; + gap: pxToRem(12px); + margin-top: pxToRem(24px); + + button { + flex: 1; + } + } +} diff --git a/src/components/InfoTooltip/index.tsx b/src/components/InfoTooltip/index.tsx new file mode 100644 index 0000000..e7156a5 --- /dev/null +++ b/src/components/InfoTooltip/index.tsx @@ -0,0 +1,30 @@ +import { FloaterPlacement, Icon, Tooltip } from "@stellar/design-system"; +import "./styles.scss"; + +interface InfoTooltipProps { + children: React.ReactNode; + infoText: React.ReactNode; + placement?: FloaterPlacement; +} + +export const InfoTooltip = ({ + children, + infoText, + placement = "right", +}: InfoTooltipProps) => { + return ( +
+ {children} + + +
+ } + placement={placement} + > + {infoText} + + + ); +}; diff --git a/src/components/InfoTooltip/styles.scss b/src/components/InfoTooltip/styles.scss new file mode 100644 index 0000000..213c898 --- /dev/null +++ b/src/components/InfoTooltip/styles.scss @@ -0,0 +1,35 @@ +@use "../../styles-utils.scss" as *; + +.InfoTooltip { + display: inline-flex; + align-items: center; + gap: pxToRem(5px); + position: relative; + + // Make sure tooltip covers other info buttons + &:has(.trigger--active) { + z-index: var(--z-index-tooltip); + } + + &__button { + width: pxToRem(14px); + height: pxToRem(24px); + cursor: pointer; + display: flex; + align-items: center; + color: var(--color-gray-60); + + svg { + display: block; + width: pxToRem(12px); + height: pxToRem(12px); + fill: currentColor; + } + + @media (hover: hover) { + &:hover { + color: var(--color-gray-70); + } + } + } +} diff --git a/src/components/InnerPage/index.tsx b/src/components/InnerPage/index.tsx new file mode 100644 index 0000000..23c0830 --- /dev/null +++ b/src/components/InnerPage/index.tsx @@ -0,0 +1,185 @@ +import React from "react"; +import { useDispatch } from "react-redux"; +import { NavLink } from "react-router-dom"; +import { Icon } from "@stellar/design-system"; + +import { PageHeader } from "components/PageHeader"; +import { + LOCAL_STORAGE_SESSION_TOKEN, + Routes, + USE_SSO, +} from "constants/settings"; +import { AppDispatch, resetStoreAction } from "store"; +import { useRedux } from "hooks/useRedux"; +import { singleUserStore } from "helpers/singleSingOn"; +import { getAppVersion } from "helpers/getAppVersion"; + +import "./styles.scss"; + +interface InnerPageProps { + children: React.ReactElement; + isNarrow?: boolean; + // Used in Sign in, Forgot password, and similar pages + isCardLayout?: boolean; +} + +export const InnerPage = ({ + children, + isNarrow, + isCardLayout, +}: InnerPageProps) => { + const { userAccount, organization, profile } = useRedux( + "userAccount", + "organization", + "profile", + ); + const dispatch: AppDispatch = useDispatch(); + + const handleSignOut = () => { + if (USE_SSO) { + // reset user store (from session storage) + singleUserStore().then(); + } + dispatch(resetStoreAction()); + localStorage.removeItem(LOCAL_STORAGE_SESSION_TOKEN); + }; + + type NavItem = { + id: string; + label: string; + route: string; + icon: React.ReactNode; + }; + + const ITEMS_TOP: NavItem[] = [ + { + id: "nav-home", + label: "Home", + route: Routes.HOME, + icon: , + }, + { + id: "nav-disbursements", + label: "Disbursements", + route: Routes.DISBURSEMENTS, + icon: , + }, + { + id: "nav-receivers", + label: "Receivers", + route: Routes.RECEIVERS, + icon: , + }, + { + id: "nav-payments", + label: "Payments", + route: Routes.PAYMENTS, + icon: , + }, + { + id: "nav-wallets", + label: "Wallets", + route: Routes.WALLETS, + icon: , + }, + { + id: "nav-analytics", + label: "Analytics", + route: Routes.ANALYTICS, + icon: , + }, + ]; + + const ITEMS_BOTTOM: NavItem[] = [ + { + id: "nav-profile", + label: "Profile", + route: Routes.PROFILE, + icon: , + }, + { + id: "nav-settings", + label: "Settings", + route: Routes.SETTINGS, + icon: , + }, + ]; + + const navLinkStyle = ({ isActive }: { isActive: boolean }) => { + return ["Sidebar__navItem", isActive ? "Sidebar__navItem--current" : null] + .filter(Boolean) + .join(" "); + }; + + const NavItem = ({ item }: { item: NavItem }) => ( + + {item.icon} + {item.label} + + ); + + const userNameText = () => { + if (profile.data.firstName) { + if (profile.data.lastName) { + return `${profile.data.firstName} ${profile.data.lastName + .charAt(0) + .toUpperCase()}.`; + } + + return profile.data.firstName; + } + + return profile.data.email; + }; + + if (isCardLayout) { + return ( + <> + +
+
+
+ {children} +
+
+
+ + ); + } + + return ( + <> + +
+
+
+ {ITEMS_TOP.map((i) => ( + + ))} +
+
+ {ITEMS_BOTTOM.map((i) => ( + + ))} + +
v{getAppVersion()}
+
+
+
+
+ {children} +
+
+
+ + ); +}; diff --git a/src/components/InnerPage/styles.scss b/src/components/InnerPage/styles.scss new file mode 100644 index 0000000..36e2311 --- /dev/null +++ b/src/components/InnerPage/styles.scss @@ -0,0 +1,99 @@ +@use "./styles-utils.scss" as *; + +.InnerPage { + display: flex; + height: calc(100vh - pxToRem(65px)); + + &__sidebar { + width: pxToRem(242px); + flex-shrink: 0; + flex-grow: 0; + border-right: 1px solid var(--color-gray-40); + display: flex; + flex-direction: column; + overflow: auto; + + &--top, + &--bottom { + padding: pxToRem(32px); + display: flex; + flex-direction: column; + gap: pxToRem(12px); + } + + &--top { + flex: 1; + } + + &--bottom { + flex: 1; + justify-content: flex-end; + } + } + + &__container { + flex: 1; + overflow: auto; + } + + &__content { + padding: pxToRem(32px); + color: var(--color-gray-90); + width: calc(pxToRem(1134px) + pxToRem(32px) * 2); + margin-left: auto; + margin-right: auto; + + &--narrow { + width: pxToRem(584px); + padding-left: 0; + padding-right: 0; + margin-left: auto; + margin-right: auto; + } + } +} + +.Sidebar { + &__navItem { + display: flex; + align-items: center; + gap: pxToRem(16px); + font-size: pxToRem(14px); + line-height: pxToRem(22px); + font-weight: var(--font-weight-medium); + color: var(--color-gray-60); + text-decoration: none; + transition: all var(--anim-transition-default); + + &__icon { + display: block; + width: pxToRem(14px); + height: pxToRem(14px); + + svg { + display: block; + width: 100%; + height: 100%; + fill: currentColor; + } + } + + @media (hover: hover) { + &:hover { + color: var(--color-gray-90); + } + } + + &--current { + color: var(--color-gray-90); + cursor: default; + } + } + + &__item { + font-size: pxToRem(10px); + line-height: pxToRem(16px); + font-weight: var(--font-weight-semi-bold); + color: var(--color-gray-60); + } +} diff --git a/src/components/MoreMenuButton.tsx b/src/components/MoreMenuButton.tsx new file mode 100644 index 0000000..9054a28 --- /dev/null +++ b/src/components/MoreMenuButton.tsx @@ -0,0 +1,7 @@ +import { Icon } from "@stellar/design-system"; + +export const MoreMenuButton = (props: React.HTMLAttributes) => ( +
+ +
+); diff --git a/src/components/MultipleAmounts/index.tsx b/src/components/MultipleAmounts/index.tsx new file mode 100644 index 0000000..be0cdd9 --- /dev/null +++ b/src/components/MultipleAmounts/index.tsx @@ -0,0 +1,41 @@ +import { AssetAmount } from "components/AssetAmount"; +import { DropdownMenu } from "components/DropdownMenu"; +import { AmountReceived } from "types"; +import "./styles.scss"; + +export const MultipleAmounts = ({ amounts }: { amounts: AmountReceived[] }) => { + if (amounts.length === 0) { + return <>"-"; + } + + if (amounts.length === 1) { + return ( + + ); + } + + const firstItem = amounts[0]; + const remainingItems = amounts.slice(1); + + return ( +
+ +{remainingItems.length}
+ } + > +
+ {remainingItems.map((i) => ( +
+ +
+ ))} +
+ + + + ); +}; diff --git a/src/components/MultipleAmounts/styles.scss b/src/components/MultipleAmounts/styles.scss new file mode 100644 index 0000000..9924ee2 --- /dev/null +++ b/src/components/MultipleAmounts/styles.scss @@ -0,0 +1,31 @@ +@use "./styles-utils.scss" as *; + +.MultipleAmounts { + display: inline-flex !important; + gap: pxToRem(4px); + align-items: center; + + &__count { + background-color: var(--color-gray-30); + border-radius: pxToRem(4px); + color: var(--color-gray-60); + font-size: pxToRem(12px); + line-height: pxToRem(20px); + font-weight: var(--font-weight-medium); + text-align: center; + padding: 1px pxToRem(4px); + cursor: pointer; + } + + &__container { + padding: pxToRem(8px); + display: flex; + flex-direction: column; + + & > *:not(:first-child) { + border-top: 1px solid var(--color-gray-30); + padding-top: pxToRem(6px); + margin-top: pxToRem(6px); + } + } +} diff --git a/src/components/NewDisbursementButton.tsx b/src/components/NewDisbursementButton.tsx new file mode 100644 index 0000000..75db20d --- /dev/null +++ b/src/components/NewDisbursementButton.tsx @@ -0,0 +1,26 @@ +import { Button, Icon } from "@stellar/design-system"; +import { useNavigate } from "react-router-dom"; +import { ShowForRoles } from "components/ShowForRoles"; +import { Routes } from "constants/settings"; + +export const NewDisbursementButton = () => { + const navigate = useNavigate(); + + const goToNewDisbursement = () => { + navigate(Routes.DISBURSEMENT_NEW); + }; + + return ( + + + + ); +}; diff --git a/src/components/NewUserModal.tsx b/src/components/NewUserModal.tsx new file mode 100644 index 0000000..221c9ea --- /dev/null +++ b/src/components/NewUserModal.tsx @@ -0,0 +1,223 @@ +import { useCallback, useEffect, useState } from "react"; +import { Button, Icon, Input, Modal, Select } from "@stellar/design-system"; +import { InfoTooltip } from "components/InfoTooltip"; +import { USER_ROLES_ARRAY } from "constants/settings"; +import { userRoleText } from "helpers/userRoleText"; +import { useRedux } from "hooks/useRedux"; +import { NewUser, UserRole } from "types"; + +interface NewUserModalProps { + visible: boolean; + onClose: () => void; + onSubmit: (newUser: NewUser) => void; + isLoading: boolean; +} + +export const NewUserModal: React.FC = ({ + visible, + onClose, + onSubmit, + isLoading, +}: NewUserModalProps) => { + type FormItems = { + fname?: string; + lname?: string; + email?: string; + role?: UserRole; + }; + + const initForm = { + fname: "", + lname: "", + email: "", + role: undefined, + }; + + const { users } = useRedux("users"); + + const [formItems, setFormItems] = useState(initForm); + const [formError, setFormError] = useState([]); + + const handleClose = useCallback(() => { + setFormItems({}); + setFormError([]); + onClose(); + }, [onClose]); + + useEffect(() => { + if ( + users.newUser.status === "ERROR" || + users.newUser.status === "SUCCESS" + ) { + handleClose(); + } + }, [handleClose, users.newUser.status]); + + const filledItems = () => Object.values(formItems).filter((v) => v); + + const canSubmit = formError.length === 0 && filledItems().length === 4; + + const removeItemFromErrors = (id: string) => { + setFormError(formError.filter((e) => e !== id)); + }; + + const handleChange = ( + event: + | React.ChangeEvent + | React.ChangeEvent, + ) => { + removeItemFromErrors(event.target.id); + setFormItems({ + ...formItems, + [event.target.id]: event.target.value, + }); + }; + + const handleValidate = ( + event: + | React.ChangeEvent + | React.ChangeEvent, + ) => { + if (!event.target.value) { + if (!formError.includes(event.target.value)) { + setFormError([...formError, event.target.id]); + } + } + }; + + const itemHasError = (id: string, label: string) => { + return formError.includes(id) ? `${label} is required` : undefined; + }; + + const roleDescription = (role?: UserRole) => { + switch (role) { + case "business": + return "Has read access to data, cannot submit new disbursements or manage users"; + case "developer": + return "Has access to help technically troubleshoot, cannot view data or submit disbursements"; + case "financial_controller": + return "Has read access to data, can submit new disbursements, cannot manage users"; + case "owner": + return "Has full access over disbursements and account management"; + default: + return "Select a role to see the level of permissions"; + } + }; + + return ( + + + + Invite team members + + +
{ + event.preventDefault(); + + // Checking all fields manually to make TS happy in onSubmit method + if ( + !( + formItems.fname && + formItems.lname && + formItems.email && + formItems.role + ) + ) { + return; + } + + onSubmit({ + first_name: formItems.fname, + last_name: formItems.lname, + email: formItems.email, + role: formItems.role, + }); + }} + onReset={handleClose} + > + +
+ + + + +
+ + {roleDescription(formItems.role)} +
+
+
+ + + + +
+
+ ); +}; diff --git a/src/components/NotificationWithButtons/index.tsx b/src/components/NotificationWithButtons/index.tsx new file mode 100644 index 0000000..ae56447 --- /dev/null +++ b/src/components/NotificationWithButtons/index.tsx @@ -0,0 +1,37 @@ +import { Link, Notification } from "@stellar/design-system"; +import "./styles.scss"; + +interface NotificationWithButtonsProps { + variant: "primary" | "secondary" | "success" | "error" | "warning"; + title: string; + icon?: React.ReactNode; + buttons: { + label: string; + onClick: () => void; + }[]; + children: string | React.ReactNode; +} + +export const NotificationWithButtons: React.FC< + NotificationWithButtonsProps +> = ({ + variant, + title, + icon, + buttons, + children, +}: NotificationWithButtonsProps) => { + return ( + +
{children}
+ +
+ {buttons.map((b) => ( + + {b.label} + + ))} +
+
+ ); +}; diff --git a/src/components/NotificationWithButtons/styles.scss b/src/components/NotificationWithButtons/styles.scss new file mode 100644 index 0000000..62e16fd --- /dev/null +++ b/src/components/NotificationWithButtons/styles.scss @@ -0,0 +1,17 @@ +@use "./styles-utils.scss" as *; + +.Notification { + &__buttons { + display: flex; + align-items: center; + justify-content: flex-end; + gap: pxToRem(12px); + margin-top: pxToRem(8px); + + .Link--primary { + --Link-color-default: var(--color-gray-90); + --Link-color-hover: var(--color-gray-80); + --Link-color-disabled: var(--color-gray-70); + } + } +} diff --git a/src/components/PageHeader/index.tsx b/src/components/PageHeader/index.tsx new file mode 100644 index 0000000..e5916b8 --- /dev/null +++ b/src/components/PageHeader/index.tsx @@ -0,0 +1,78 @@ +/* eslint-disable jsx-a11y/anchor-is-valid */ +import { Button, Icon, Logo, ThemeSwitch } from "@stellar/design-system"; +import { PROJECT_NAME, Routes } from "constants/settings"; +import { DropdownMenu } from "components/DropdownMenu"; +import { formatDateTimeWithGmt } from "helpers/formatIntlDateTime"; +import "./styles.scss"; + +type PageHeaderProps = { + username?: string; + onSignOut?: () => void; + logoImage?: string; + companyName?: string; +}; + +export const PageHeader = ({ + username, + onSignOut, + logoImage, + companyName, +}: PageHeaderProps) => { + return ( +
+
+
+ {username ? ( +
+
+
+ {companyName || "Company Name"} +
+
+ ) : ( + + )} +
+
+ +
+
+ {username ? ( +
+
+ + + + {formatDateTimeWithGmt()} +
+
+ ) : null} +
+ {username ? ( + + {username} + + } + > + + Profile + + Help + + Sign out + + + ) : null} + + +
+
+
+
+ ); +}; diff --git a/src/components/PageHeader/styles.scss b/src/components/PageHeader/styles.scss new file mode 100644 index 0000000..f2676f5 --- /dev/null +++ b/src/components/PageHeader/styles.scss @@ -0,0 +1,115 @@ +@use "./styles-utils.scss" as *; + +.PageHeader { + display: flex; + position: relative; + z-index: calc(var(--z-index-tooltip) + 1); + + &__content { + flex: 1; + } + + &__inset { + height: pxToRem(32px); + margin-top: pxToRem(16px); + margin-bottom: pxToRem(16px); + display: flex; + align-items: center; + gap: pxToRem(12px); + padding: 0 pxToRem(32px); + } + + &__logo { + display: block; + margin-left: pxToRem(-8px); + height: 100%; + min-width: pxToRem(calc(242px - (28px * 2))); + flex-shrink: 0; + + svg { + display: block; + fill: var(--color-gray-90); + height: 100%; + width: 100%; + } + } + + &--left, + &--right { + display: flex; + align-items: center; + flex: 1; + gap: pxToRem(12px); + } + + &--left { + justify-content: flex-start; + } + + &--right { + justify-content: flex-end; + } + + &--internal { + border-bottom: 1px solid var(--color-gray-40); + } +} + +// Company brand +.CompanyBrand { + display: flex; + align-items: center; + gap: pxToRem(12px); + height: pxToRem(32px); + + &__logo { + height: pxToRem(32px); + min-width: pxToRem(32px); + border-radius: pxToRem(16px); + background-color: var(--color-gray-00); + flex-shrink: 0; + flex-grow: 0; + overflow: hidden; + position: relative; + + background-size: cover; + background-position: center center; + + img { + height: 100%; + display: block; + position: absolute; + } + } + &__name { + font-size: pxToRem(14px); + line-height: pxToRem(22px); + font-weight: var(--font-weight-medium); + color: var(--color-gray-70); + flex: 1; + } +} + +// Datetime +.DateTime { + display: flex; + align-items: center; + gap: pxToRem(8px); + font-size: pxToRem(14px); + line-height: pxToRem(22px); + font-weight: var(--font-weight-medium); + color: var(--color-gray-60); + + &__icon { + display: block; + width: pxToRem(14px); + height: pxToRem(14px); + + svg { + display: block; + width: 100%; + height: 100%; + fill: currentColor; + } + } +} diff --git a/src/components/Pagination/index.tsx b/src/components/Pagination/index.tsx new file mode 100644 index 0000000..10744c7 --- /dev/null +++ b/src/components/Pagination/index.tsx @@ -0,0 +1,70 @@ +import { Button, Icon, Input } from "@stellar/design-system"; +import "./styles.scss"; + +interface PaginationProps { + currentPage: number; + maxPages: number; + onChange: (event: React.ChangeEvent) => void; + onBlur: (currentPage: number) => void; + onPrevious: (event: React.MouseEvent) => void; + onNext: (event: React.MouseEvent) => void; + isLoading: boolean; +} + +export const Pagination = ({ + currentPage, + maxPages, + onChange, + onBlur, + onPrevious, + onNext, + isLoading, +}: PaginationProps) => { + const isError = currentPage > maxPages; + + const handleBlur = ( + event: + | React.FormEvent + | React.FocusEvent, + ) => { + event.preventDefault(); + + if (!isError) { + onBlur(currentPage); + } + }; + + return ( +
+ Page +
+ +
+ of {maxPages} +
+
+
+ ); +}; diff --git a/src/components/Pagination/styles.scss b/src/components/Pagination/styles.scss new file mode 100644 index 0000000..554f60e --- /dev/null +++ b/src/components/Pagination/styles.scss @@ -0,0 +1,52 @@ +@use "./styles-utils.scss" as *; + +.Pagination-v2 { + display: flex; + align-items: center; + gap: pxToRem(4px); + flex-shrink: 0; + + font-size: pxToRem(12px); + line-height: pxToRem(20px); + font-weight: var(--font-weight-regular); + color: var(--color-gray-80); + + span { + flex-shrink: 0; + } + + &__input { + width: pxToRem(50px); + flex-shrink: 0; + + input { + text-align: center; + font-size: pxToRem(12px); + line-height: pxToRem(20px); + height: pxToRem(34px); + } + } + + &__buttons { + display: flex; + align-items: center; + margin-left: pxToRem(8px); + + button { + width: pxToRem(36px); + height: pxToRem(36px); + border-radius: pxToRem(2px); + + &:first-child { + border-right-color: transparent; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + + &:last-child { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + } + } +} diff --git a/src/components/PaymentStatus/index.tsx b/src/components/PaymentStatus/index.tsx new file mode 100644 index 0000000..7a6ac4c --- /dev/null +++ b/src/components/PaymentStatus/index.tsx @@ -0,0 +1,23 @@ +import { PaymentStatus as PaymentStatusType } from "types"; +import "./styles.scss"; + +export const PaymentStatus = ({ status }: { status: PaymentStatusType }) => { + switch (status) { + case "DRAFT": + return Draft; + case "FAILED": + return Failed; + case "PAUSED": + return Paused; + case "PENDING": + return Pending; + case "READY": + return Ready; + case "SUCCESS": + return ( + Success + ); + default: + return null; + } +}; diff --git a/src/components/PaymentStatus/styles.scss b/src/components/PaymentStatus/styles.scss new file mode 100644 index 0000000..367cc77 --- /dev/null +++ b/src/components/PaymentStatus/styles.scss @@ -0,0 +1,7 @@ +.PaymentStatus { + color: currentColor; + + &--accent { + color: var(--color-green-60); + } +} diff --git a/src/components/PaymentsTable.tsx b/src/components/PaymentsTable.tsx new file mode 100644 index 0000000..321fd38 --- /dev/null +++ b/src/components/PaymentsTable.tsx @@ -0,0 +1,147 @@ +import { useNavigate } from "react-router-dom"; +import { Link, Profile, Notification, Card } from "@stellar/design-system"; +import { Routes } from "constants/settings"; + +import { AssetAmount } from "components/AssetAmount"; +import { PaymentStatus } from "components/PaymentStatus"; +import { Table } from "components/Table"; +import { formatDateTime } from "helpers/formatIntlDateTime"; +import { ApiPayment, ActionStatus } from "types"; + +interface PaymentsTableProps { + paymentItems: ApiPayment[]; + apiError: string | boolean | undefined; + isFiltersSelected: boolean | undefined; + status: ActionStatus | undefined; +} + +export const PaymentsTable = ({ + paymentItems, + apiError, + isFiltersSelected, + status, +}: PaymentsTableProps) => { + const navigate = useNavigate(); + + const handlePaymentClicked = ( + event: React.MouseEvent, + paymentId: string, + ) => { + event.preventDefault(); + navigate(`${Routes.PAYMENTS}/${paymentId}`); + }; + + const handlePaymentDisbursementClicked = ( + event: React.MouseEvent, + disbursementId: string, + ) => { + event.preventDefault(); + navigate(`${Routes.DISBURSEMENTS}/${disbursementId}`); + }; + + if (apiError) { + return ( + + {apiError} + + ); + } + + if (paymentItems?.length === 0) { + if (status === "PENDING") { + return
Loading…
; + } + + if (isFiltersSelected) { + return ( +
+ There are no payments matching your selected filters +
+ ); + } + + return
There are no payments
; + } + + return ( +
+ + + + {/* TODO: put back once ready */} + {/* + + */} + Payment ID + Wallet address + Disbursement name + Completed at + + Amount + + + Status + + + + + {paymentItems.map((p, index) => ( + // Using index here to make sure UI works if we have duplicate entries + // Otherwise, table data is not updating + + {/* TODO: put back once ready */} + {/* + + */} + + handlePaymentClicked(event, p.id)}> + {p.id} + + + + {p.receiver_wallet?.stellar_address ? ( + + ) : ( + "-" + )} + + + + handlePaymentDisbursementClicked(event, p.disbursement.id) + } + > + {p.disbursement.name} + + + + + {p.status === "SUCCESS" + ? formatDateTime(p.updated_at) + : "-"} + + + + + + + + + + ))} + +
+
+
+ ); +}; diff --git a/src/components/PrivateRoute.tsx b/src/components/PrivateRoute.tsx new file mode 100644 index 0000000..b269ffb --- /dev/null +++ b/src/components/PrivateRoute.tsx @@ -0,0 +1,43 @@ +import { Navigate, useLocation } from "react-router-dom"; +import { useRedux } from "hooks/useRedux"; +import { UserRole } from "types"; + +export const PrivateRoute = ({ + children, + acceptedRoles, +}: { + children: React.ReactElement; + acceptedRoles?: UserRole[]; +}) => { + const { userAccount } = useRedux("userAccount"); + const location = useLocation(); + + const isRoleRestricted = acceptedRoles && acceptedRoles?.length > 0; + const isRoleAllowed = + userAccount.role && acceptedRoles?.includes(userAccount.role as UserRole); + + const renderContent = () => { + if (!isRoleRestricted || isRoleAllowed) { + return children; + } + + return ( + + ); + }; + + return !userAccount.isAuthenticated || userAccount.isSessionExpired ? ( + + ) : ( + renderContent() + ); +}; diff --git a/src/components/QueryStatusHandler.tsx b/src/components/QueryStatusHandler.tsx new file mode 100644 index 0000000..09e73fc --- /dev/null +++ b/src/components/QueryStatusHandler.tsx @@ -0,0 +1,37 @@ +import { Notification } from "@stellar/design-system"; + +interface QueryStatusHandlerProps { + isLoading?: boolean; + isError?: boolean; + isEmpty?: boolean; + emptyMessage?: string; + errorMessage?: string; + children: React.ReactNode; +} + +export const QueryStatusHandler = ({ + isLoading, + isError, + isEmpty, + emptyMessage = "No data", + errorMessage = "Something went wrong", + children, +}: QueryStatusHandlerProps) => { + if (isLoading) { + return
Loading…
; + } + + if (isError) { + return ( + + {errorMessage} + + ); + } + + if (isEmpty) { + return
{emptyMessage}
; + } + + return <>{children}; +}; diff --git a/src/components/ReceiverStatus/index.tsx b/src/components/ReceiverStatus/index.tsx new file mode 100644 index 0000000..c6aa2cf --- /dev/null +++ b/src/components/ReceiverStatus/index.tsx @@ -0,0 +1,23 @@ +import { ReceiverStatus as ReceiverStatusType } from "types"; +import "./styles.scss"; + +export const ReceiverStatus = ({ status }: { status: ReceiverStatusType }) => { + switch (status) { + case "DRAFT": + return Draft; + case "FLAGGED": + return Flagged; + case "READY": + return ( + Ready + ); + case "REGISTERED": + return ( + + Registered + + ); + default: + return null; + } +}; diff --git a/src/components/ReceiverStatus/styles.scss b/src/components/ReceiverStatus/styles.scss new file mode 100644 index 0000000..a05d8f7 --- /dev/null +++ b/src/components/ReceiverStatus/styles.scss @@ -0,0 +1,7 @@ +.ReceiverStatus { + color: currentColor; + + &--accent { + color: var(--color-green-60); + } +} diff --git a/src/components/ReceiverWalletBalance.tsx b/src/components/ReceiverWalletBalance.tsx new file mode 100644 index 0000000..efed869 --- /dev/null +++ b/src/components/ReceiverWalletBalance.tsx @@ -0,0 +1,59 @@ +import { Fragment, useEffect } from "react"; +import { Notification } from "@stellar/design-system"; +import { useQuery } from "@tanstack/react-query"; +import { getStellarAccountInfo } from "api/getStellarAccountInfo"; +import { AssetAmount } from "components/AssetAmount"; + +interface ReceiverWalletBalanceProps { + stellarAddress: string | undefined; +} + +export const ReceiverWalletBalance = ({ + stellarAddress, +}: ReceiverWalletBalanceProps) => { + const getBalance = async () => { + if (!stellarAddress) { + return []; + } + + const response = await getStellarAccountInfo(stellarAddress); + // We don't want to show XLM (native) balance + return response.balances.filter((b) => b.asset_issuer && b.asset_code); + }; + + const { isLoading, data, isError, error, refetch } = useQuery({ + queryKey: ["ReceiverWalletBalance"], + queryFn: getBalance, + }); + + useEffect(() => { + refetch(); + }, [stellarAddress, refetch]); + + if (isLoading) { + return
Loading…
; + } + + if (isError) { + return ( + + {error as string} + + ); + } + + if (data?.length === 0) { + return <>{"-"}; + } + + return ( + <> + {data?.map((b, index) => ( + + + {index < data.length - 1 ? ", " : null} + + ))} + + ); +}; diff --git a/src/components/ReceiverWalletHistory.tsx b/src/components/ReceiverWalletHistory.tsx new file mode 100644 index 0000000..d09a7f0 --- /dev/null +++ b/src/components/ReceiverWalletHistory.tsx @@ -0,0 +1,151 @@ +import { useEffect } from "react"; +import { Card, Link, Profile, Notification } from "@stellar/design-system"; +import { useQuery } from "@tanstack/react-query"; + +import { getStellarAccountPayments } from "api/getStellarAccountPayments"; +import { getStellarTransaction } from "api/getStellarTransaction"; +import { STELLAR_EXPERT_URL } from "constants/settings"; +import { formatDateTime } from "helpers/formatIntlDateTime"; + +import { Table } from "components/Table"; +import { AssetAmount } from "components/AssetAmount"; + +import { ApiStellarOperationRecord, ReceiverWalletPayment } from "types"; + +interface ReceiverWalletHistoryProps { + stellarAddress: string | undefined; +} + +const formatWalletPayment = async ( + payment: ApiStellarOperationRecord, + walletAddress: string, +): Promise => { + const isSend = payment.from === walletAddress; + + // Getting transaction details to get the memo + const transaction = await getStellarTransaction(payment.transaction_hash); + + return { + id: payment.id.toString(), + amount: payment.amount, + paymentAddress: isSend ? payment.to : payment.from, + createdAt: payment.created_at, + assetCode: payment.asset_code, + assetIssuer: payment.asset_issuer, + operationKind: isSend ? "send" : "receive", + transactionHash: payment.transaction_hash, + memo: transaction.memo || "", + }; +}; + +export const ReceiverWalletHistory = ({ + stellarAddress, +}: ReceiverWalletHistoryProps) => { + const getPayments = async () => { + if (!stellarAddress) { + return []; + } + + // We don't want to show XLM (native) payments + const response = (await getStellarAccountPayments(stellarAddress)).filter( + (r) => r.asset_issuer && r.asset_code, + ); + const payments = []; + + for await (const record of response) { + const payment = await formatWalletPayment(record, stellarAddress); + payments.push(payment); + } + + return payments; + }; + + const { isLoading, isError, data, error, refetch } = useQuery({ + queryKey: ["ReceiverWalletHistory"], + queryFn: getPayments, + }); + + useEffect(() => { + refetch(); + }, [stellarAddress, refetch]); + + if (isLoading) { + return
Loading…
; + } + + if (isError) { + return ( + + {error as string} + + ); + } + + return ( + + + + Operation ID + Date/time + Wallet address + Memo + Amount + + + + {data && data.length > 0 ? ( + data.map((p) => ( + + + + {p.id} + + + + + {formatDateTime(p.createdAt)} + + + + {p.paymentAddress ? ( + + ) : ( + "-" + )} + + + {p.memo ? ( + {p.memo} + ) : null} + + + {p.operationKind === "send" ? "-" : "+"} + + + + )) + ) : ( + + + + )} + +
+ No recent payments +
+
+ ); +}; diff --git a/src/components/ReceiversTable.tsx b/src/components/ReceiversTable.tsx new file mode 100644 index 0000000..1c952bd --- /dev/null +++ b/src/components/ReceiversTable.tsx @@ -0,0 +1,152 @@ +import { Card, Link, Notification } from "@stellar/design-system"; +import { formatDateTime } from "helpers/formatIntlDateTime"; +import { useSort } from "hooks/useSort"; +import { MultipleAmounts } from "components/MultipleAmounts"; +import { Table } from "components/Table"; +import { + ActionStatus, + Receiver, + ReceiversSearchParams, + SortByReceivers, + SortDirection, +} from "types"; + +interface ReceiversTableProps { + receiversItems: Receiver[]; + onReceiverClicked: ( + event: React.MouseEvent, + id: string, + ) => void; + searchParams: ReceiversSearchParams | undefined; + apiError: string | boolean | undefined; + isFiltersSelected: boolean | undefined; + status: ActionStatus | undefined; + onSort?: (sort?: SortByReceivers, direction?: SortDirection) => void; +} + +export const ReceiversTable: React.FC = ({ + receiversItems, + onReceiverClicked, + searchParams, + apiError, + isFiltersSelected, + status, + onSort, +}: ReceiversTableProps) => { + const { sortBy, sortDir, handleSort } = useSort(onSort); + + if (apiError) { + return ( + + {apiError} + + ); + } + + if (receiversItems?.length === 0) { + if (status === "PENDING") { + return
Loading…
; + } + + if (searchParams?.q) { + if (isFiltersSelected) { + return ( +
+ {`There are no receivers matching "${searchParams.q}" with selected filters`} +
+ ); + } + + return ( +
+ {`There are no receivers matching "${searchParams.q}"`} +
+ ); + } + + if (isFiltersSelected) { + return ( +
+ There are no receivers matching selected filters +
+ ); + } + + return
There are no receivers
; + } + + return ( +
+ + + + {/* TODO: put back once ready */} + {/* + + */} + Phone number + + Wallet provider(s) + + + Wallets registered + + + Total payments + + Successful + handleSort("created_at")} + > + Created at + + + Amount(s) received + + + + + {receiversItems.map((d) => ( + + {/* TODO: put back once ready */} + {/* + + */} + + onReceiverClicked(event, d.id)}> + {d.phoneNumber} + + + + {d.walletProvider.join(", ")} + + + {d.walletsRegisteredCount || "-"} + + + {d.totalPaymentsCount} + + + {d.successfulPaymentsCounts} + + + + {d.createdAt ? formatDateTime(d.createdAt) : "-"} + + + + + + + ))} + +
+
+
+ ); +}; diff --git a/src/components/RetryFailedPayment.tsx b/src/components/RetryFailedPayment.tsx new file mode 100644 index 0000000..1d9226f --- /dev/null +++ b/src/components/RetryFailedPayment.tsx @@ -0,0 +1,73 @@ +import { useEffect } from "react"; +import { Banner, Icon, Link, Loader } from "@stellar/design-system"; +import { useQuery } from "@tanstack/react-query"; +import { patchPaymentsRetry } from "api/patchPaymentsRetry"; +import { useSessionToken } from "hooks/useSessionToken"; +import { PaymentDetailsStatusHistoryItem } from "types"; + +interface RetryFailedPaymentProps { + paymentId: string; + paymentStatus: PaymentDetailsStatusHistoryItem[]; + onSuccess: () => void; +} + +export const RetryFailedPayment = ({ + paymentId, + paymentStatus, + onSuccess, +}: RetryFailedPaymentProps) => { + const sessionToken = useSessionToken(); + const isFailed = paymentStatus.slice(-1)[0]?.status === "FAILED"; + + const retryPayment = async () => { + const response = await patchPaymentsRetry(sessionToken, [paymentId]); + return response.message; + }; + + const { isFetching, data, isError, error, refetch } = useQuery({ + queryKey: ["RetryFailedPayment"], + queryFn: retryPayment, + enabled: false, + }); + + const isSuccess = Boolean(data); + + useEffect(() => { + if (isSuccess) { + onSuccess(); + } + }, [isSuccess, onSuccess]); + + if (!isFailed) { + return null; + } + + return ( +
+
+ {data ? ( + {data} + ) : ( + + <> +
+ {isError + ? (error as any).error + : "Unfortunately your payment failed. Click Retry to submit again."} +
+ refetch()} + isDisabled={isFetching} + icon={isFetching ? : } + > + Retry + + +
+ )} +
+
+ ); +}; diff --git a/src/components/SearchInput/index.tsx b/src/components/SearchInput/index.tsx new file mode 100644 index 0000000..d6d224a --- /dev/null +++ b/src/components/SearchInput/index.tsx @@ -0,0 +1,61 @@ +import { FormEvent, useState } from "react"; +import { Icon, Input, Loader } from "@stellar/design-system"; +import "./styles.scss"; + +interface SearchInputProps { + id: string; + placeholder: string; + onSubmit: (text: string) => void; + onClear: () => void; + isLoading: boolean; + disabled?: boolean; +} + +export const SearchInput = ({ + id, + placeholder, + onSubmit, + onClear, + isLoading, + disabled, +}: SearchInputProps) => { + const [searchText, setSearchText] = useState(""); + + const handleSubmit = (event: FormEvent) => { + event.preventDefault(); + onSubmit(searchText); + }; + + const handleChange = (event: FormEvent) => { + const val = event.currentTarget.value; + + if (val) { + setSearchText(val); + } else { + setSearchText(""); + onClear(); + } + }; + + return ( +
+ + + +
+ ); +}; diff --git a/src/components/SearchInput/styles.scss b/src/components/SearchInput/styles.scss new file mode 100644 index 0000000..755975e --- /dev/null +++ b/src/components/SearchInput/styles.scss @@ -0,0 +1,48 @@ +@use "./styles-utils.scss" as *; + +.SearchInput { + width: 100%; + height: pxToRem(34px); + position: relative; + + &__button { + position: absolute; + width: pxToRem(32px); + height: pxToRem(34px); + top: 1px; + right: 1px; + border: none; + border-top-right-radius: pxToRem(4px); + border-bottom-right-radius: pxToRem(4px); + background-color: transparent; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + color: var(--color-gray-80); + transition: color var(--anim-transition-default); + + svg { + width: pxToRem(14px); + height: pxToRem(14px); + fill: currentColor; + } + + &:hover { + color: var(--color-gray-70); + } + + &:disabled { + cursor: not-allowed; + color: var(--color-gray-60); + } + } + + .Input input { + padding-right: pxToRem(34px); + + &[type="search"] { + outline-offset: 0; + } + } +} diff --git a/src/components/SectionHeader/index.tsx b/src/components/SectionHeader/index.tsx new file mode 100644 index 0000000..9f16772 --- /dev/null +++ b/src/components/SectionHeader/index.tsx @@ -0,0 +1,30 @@ +import "./styles.scss"; + +const SectionHeaderRow = ({ children }: { children: React.ReactNode }) => { + return
{children}
; +}; + +const SectionHeaderContent = ({ + children, + align = "left", +}: { + children: React.ReactNode; + align?: "left" | "right"; +}) => { + const additionalClasses = [ + ...(align !== "left" ? [`SectionHeader__container--${align}`] : []), + ].join(" "); + + return ( +
+ {children} +
+ ); +}; + +export const SectionHeader = ({ children }: { children: React.ReactNode }) => { + return
{children}
; +}; + +SectionHeader.Row = SectionHeaderRow; +SectionHeader.Content = SectionHeaderContent; diff --git a/src/components/SectionHeader/styles.scss b/src/components/SectionHeader/styles.scss new file mode 100644 index 0000000..7eaf911 --- /dev/null +++ b/src/components/SectionHeader/styles.scss @@ -0,0 +1,35 @@ +@use "./styles-utils.scss" as *; + +.SectionHeader { + display: flex; + flex-direction: column; + margin-bottom: pxToRem(24px); + gap: pxToRem(24px); + + h2, + h3, + h4 { + margin: 0; + padding: 0; + color: var(--color-gray-90); + } + + &__row { + display: flex; + gap: pxToRem(8px); + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + } + + &__container { + display: flex; + gap: pxToRem(8px); + align-items: center; + flex: 1; + + &--right { + justify-content: flex-end; + } + } +} diff --git a/src/components/SettingsTeamMembers.tsx b/src/components/SettingsTeamMembers.tsx new file mode 100644 index 0000000..188be01 --- /dev/null +++ b/src/components/SettingsTeamMembers.tsx @@ -0,0 +1,267 @@ +import { useEffect, useState } from "react"; +import { useDispatch } from "react-redux"; +import { Button, Card, Icon, Modal } from "@stellar/design-system"; + +import { InfoTooltip } from "components/InfoTooltip"; +import { DropdownMenu } from "components/DropdownMenu"; +import { MoreMenuButton } from "components/MoreMenuButton"; +import { Table } from "components/Table"; +import { NewUserModal } from "components/NewUserModal"; + +import { AppDispatch } from "store"; +import { + changeUserRoleAction, + changeUserStatusAction, + createNewUserAction, + getUsersAction, + resetNewUserAction, +} from "store/ducks/users"; +import { USER_ROLES_ARRAY } from "constants/settings"; +import { useRedux } from "hooks/useRedux"; +import { userRoleText } from "helpers/userRoleText"; +import { ApiUser, NewUser, UserRole } from "types"; + +interface SettingsTeamMembersProps { + getUserNameText: (firstName?: string, lastName?: string) => void; +} + +export const SettingsTeamMembers = ({ + getUserNameText, +}: SettingsTeamMembersProps) => { + const { users } = useRedux("users"); + + const [selectedUser, setSelectedUser] = useState(null); + const [isStatusModalVisible, setIsStatusModalVisible] = useState(false); + const [isRoleModalVisible, setIsRoleModalVisible] = useState(false); + const [isNewUserModalVisible, setIsNewUserModalVisible] = useState(false); + const [newRole, setNewRole] = useState(null); + + const dispatch: AppDispatch = useDispatch(); + + useEffect(() => { + if (!users.status) { + dispatch(getUsersAction()); + } + }, [dispatch, users.status]); + + useEffect(() => { + if (users.updatedUser.actionType) { + dispatch(getUsersAction()); + hideModal(); + } + }, [dispatch, users.updatedUser.actionType]); + + useEffect(() => { + if (users.newUser.id) { + dispatch(getUsersAction()); + hideModal(); + } + }, [dispatch, users.newUser.id]); + + const hideModal = () => { + setIsStatusModalVisible(false); + setIsRoleModalVisible(false); + setIsNewUserModalVisible(false); + setSelectedUser(null); + setNewRole(null); + }; + + const handleStatusChange = (userId: string, isActive: boolean) => { + dispatch(changeUserStatusAction({ userId, isActive })); + }; + + const handleRoleChange = (userId: string, userRole: UserRole) => { + dispatch(changeUserRoleAction({ userId, role: userRole })); + }; + + const handleSubmitNewUser = (newUser: NewUser) => { + dispatch(createNewUserAction(newUser)); + }; + + const renderRoleItems = (user: ApiUser) => { + const currentRole = user?.roles?.[0]; + const acceptedRoles = USER_ROLES_ARRAY; + const displayRoles = acceptedRoles.filter((r) => r !== currentRole); + + return displayRoles.map((r) => ( + { + setSelectedUser(user); + setIsRoleModalVisible(true); + setNewRole(r); + }} + > + {`Change role to ${userRoleText(r)}`} + + )); + }; + + const renderUsersContent = () => { + if (users.errorString) { + return null; + } + + if (users.items.length === 0) { + return
There are no team members
; + } + + return ( +
+ + + Member + Role + Status + + + + + {users.items.map((u) => ( + + + {u.first_name || u.last_name + ? `${u.first_name} ${u.last_name}` + : u.email} + + + {userRoleText(u.roles?.[0])} + + + {u.is_active ? "Active" : "Inactive"} + + +
+ }> + <>{renderRoleItems(u)} + { + setSelectedUser(u); + setIsStatusModalVisible(true); + }} + isHighlight + > + {u.is_active ? "Deactivate" : "Activate"} + + +
+
+
+ ))} +
+
+
+ ); + }; + + return ( + <> + +
+
+ + Team members + + +
{ + setIsNewUserModalVisible(true); + dispatch(resetNewUserAction()); + }} + > + +
+
+ + {renderUsersContent()} +
+
+ + {/* Status modal */} + + + {selectedUser?.is_active ? "Deactivate account" : "Activate account"} + + +
+ {`Please confirm account ${ + selectedUser?.is_active ? "deactivation" : "activation" + } for ${getUserNameText( + selectedUser?.first_name, + selectedUser?.last_name, + )}.`} +
+
+ + + + +
+ + {/* Role modal */} + + Change role + +
+ {`Please confirm the role change from "${userRoleText( + selectedUser?.roles?.[0], + )}" to "${userRoleText(newRole)}" for ${getUserNameText( + selectedUser?.first_name, + selectedUser?.last_name, + )}.`} +
+
+ + + + +
+ + {/* New user modal */} + + + ); +}; diff --git a/src/components/SettingsTimezone.tsx b/src/components/SettingsTimezone.tsx new file mode 100644 index 0000000..03bb179 --- /dev/null +++ b/src/components/SettingsTimezone.tsx @@ -0,0 +1,143 @@ +import { useEffect, useState } from "react"; +import { useDispatch } from "react-redux"; +import { Button, Card, Select, Notification } from "@stellar/design-system"; +import { InfoTooltip } from "components/InfoTooltip"; +import { DropdownMenu } from "components/DropdownMenu"; +import { MoreMenuButton } from "components/MoreMenuButton"; +import { NotificationWithButtons } from "components/NotificationWithButtons"; +import { TIME_ZONES } from "constants/settings"; +import { useRedux } from "hooks/useRedux"; +import { AppDispatch } from "store"; +import { + updateOrgInfoAction, + clearUpdateMessageAction, + getOrgInfoAction, +} from "store/ducks/organization"; + +export const SettingsTimezone = () => { + const { organization } = useRedux("organization"); + + const [isEdit, setIsEdit] = useState(false); + const [newTimezone, setNewTimezone] = useState(""); + + const dispatch: AppDispatch = useDispatch(); + + useEffect(() => { + if (organization.updateMessage) { + dispatch(getOrgInfoAction()); + resetState(); + } + }, [dispatch, organization.updateMessage]); + + useEffect(() => { + return () => { + dispatch(clearUpdateMessageAction()); + }; + }, [dispatch]); + + const resetState = () => { + setIsEdit(false); + setNewTimezone(""); + }; + + const handleCancel = (event: React.FormEvent) => { + event.preventDefault(); + resetState(); + }; + + const handleSubmit = (event: React.FormEvent) => { + event.preventDefault(); + if (newTimezone) { + dispatch(updateOrgInfoAction({ timezone: newTimezone })); + } + }; + + return ( + <> + {organization.updateMessage ? ( + { + dispatch(clearUpdateMessageAction()); + }, + }, + ]} + > + {organization.updateMessage} + + ) : null} + + {organization.errorString ? ( + + {organization.errorString} + + ) : null} + + +
+
+ + Timezone + + + }> + { + setIsEdit(true); + setNewTimezone(organization.data.timezoneUtcOffset); + }} + > + Edit timezone + + +
+ +
+
+ +
+ + {isEdit ? ( +
+ + +
+ ) : null} +
+
+
+ + ); +}; diff --git a/src/components/ShowForRoles.tsx b/src/components/ShowForRoles.tsx new file mode 100644 index 0000000..949512e --- /dev/null +++ b/src/components/ShowForRoles.tsx @@ -0,0 +1,16 @@ +import { useIsUserRoleAccepted } from "hooks/useIsUserRoleAccepted"; +import { UserRole } from "types"; + +interface ShowForRolesProps { + acceptedRoles: UserRole[]; + children: React.ReactNode; +} + +export const ShowForRoles: React.FC = ({ + acceptedRoles, + children, +}: ShowForRolesProps) => { + const { isRoleAccepted } = useIsUserRoleAccepted(acceptedRoles); + + return isRoleAccepted ? <>{children} : null; +}; diff --git a/src/components/Table/index.tsx b/src/components/Table/index.tsx new file mode 100644 index 0000000..b744f57 --- /dev/null +++ b/src/components/Table/index.tsx @@ -0,0 +1,167 @@ +import { Icon } from "@stellar/design-system"; +import { SortDirection } from "types"; +import "./styles.scss"; + +interface HeaderProps { + children: JSX.Element | JSX.Element[]; +} + +const Header: React.FC = ({ children }: HeaderProps) => { + return ( + + {children} + + ); +}; + +interface HeaderCellProps extends React.HTMLAttributes { + children: React.ReactNode; + textAlign?: "left" | "right" | "center"; + elementLeft?: React.ReactNode; + sortDirection?: SortDirection; + onSort?: () => void; + width?: string; +} + +const HeaderCell: React.FC = ({ + children, + textAlign = "left", + elementLeft, + sortDirection, + onSort, + width, + ...props +}: HeaderCellProps) => { + if (sortDirection && onSort === undefined) { + throw Error("onSort method is required for sorting"); + } + + const SortIconEl = () => + sortDirection ? ( + + + + + ) : null; + + const sortButtonProps = sortDirection + ? { + onClick: onSort, + role: "button", + } + : {}; + + return ( + + {elementLeft || sortDirection ? ( + + {elementLeft ?? null} {children} + + ) : ( + children + )} + + ); +}; + +interface BodyProps { + children: JSX.Element | JSX.Element[]; +} + +const Body: React.FC = ({ children }: BodyProps) => { + return {children}; +}; + +interface BodyRowProps { + children: JSX.Element | JSX.Element[]; + isHighlighted?: boolean; +} + +const BodyRow: React.FC = ({ + children, + isHighlighted, +}: BodyRowProps) => { + return ( + + {children} + + ); +}; + +interface BodyCellProps extends React.HTMLAttributes { + children: React.ReactNode; + width?: string; + textAlign?: "left" | "right" | "center"; + allowOverflow?: boolean; +} + +const BodyCell: React.FC = ({ + children, + width, + textAlign = "left", + allowOverflow, + ...props +}: BodyCellProps) => { + return ( + + {width ? ( + + {children} + + ) : ( + children + )} + + ); +}; + +interface TableComponent { + Header: React.FC; + HeaderCell: React.FC; + Body: React.FC; + BodyRow: React.FC; + BodyCell: React.FC; +} + +interface TableProps extends React.HtmlHTMLAttributes { + children: JSX.Element[]; +} + +export const Table: React.FC & TableComponent = ({ + children, +}: TableProps) => { + return ( +
+
+ {children}
+
+
+ ); +}; + +Table.displayName = "Table"; +Table.Header = Header; +Table.Header.displayName = "Table.Header"; +Table.HeaderCell = HeaderCell; +Table.HeaderCell.displayName = "Table.HeaderCell"; +Table.Body = Body; +Table.Body.displayName = "Table.Body"; +Table.BodyRow = BodyRow; +Table.BodyRow.displayName = "Table.BodyRow"; +Table.BodyCell = BodyCell; +Table.BodyCell.displayName = "Table.BodyCell"; diff --git a/src/components/Table/styles.scss b/src/components/Table/styles.scss new file mode 100644 index 0000000..5490939 --- /dev/null +++ b/src/components/Table/styles.scss @@ -0,0 +1,156 @@ +@use "./styles-utils.scss" as *; + +.Table-v2__container { + width: 100%; + position: relative; +} + +.Table-v2__wrapper { + overflow-x: auto; + overflow-y: hidden; +} + +table.Table-v2 { + width: 100%; + border-collapse: collapse; + + thead tr, + tr:not(:last-child) { + border-bottom: 1px solid var(--color-gray-30); + transition: background-color linear var(--anim-transition-default); + + &.Table-v2__row--highlighted { + background-color: var(--color-gray-10); + } + } + + th, + td { + box-sizing: content-box; + padding-top: pxToRem(12px); + padding-bottom: pxToRem(12px); + padding-right: pxToRem(24px); + + &:first-child { + padding-left: pxToRem(24px); + } + + // To truncate long text + & > * { + max-width: 100%; + } + } + + th { + font-size: pxToRem(12px); + line-height: pxToRem(20px); + font-weight: var(--font-weight-medium); + color: var(--color-gray-60); + text-align: left; + + .Table-v2__header__cell { + display: flex; + gap: pxToRem(3px); + align-items: center; + + &[role="button"] { + cursor: pointer; + transition: color var(--anim-transition-default), + fill var(--anim-transition-default); + + @media (hover: hover) { + &:hover { + color: var(--color-gray-90); + + .Table-v2__header__cell__sortIcon svg { + fill: var(--color-gray-90); + } + } + } + } + + svg { + display: block; + fill: currentColor; + width: pxToRem(12px); + height: pxToRem(12px); + } + + &__sortIcon { + display: block; + position: relative; + width: pxToRem(16px); + height: pxToRem(20px); + + svg { + width: 100%; + fill: currentColor; + position: absolute; + left: 0; + transition: fill var(--anim-transition-default); + + &:nth-child(1) { + top: 0; + } + + &:nth-child(2) { + bottom: 0; + } + } + } + } + + &[data-text-align="right"] { + text-align: right; + + .Table-v2__header__cell { + justify-content: flex-end; + } + } + + &[aria-sort="ascending"], + &[aria-sort="descending"] { + color: var(--color-gray-90); + } + + &[aria-sort="ascending"] { + .Table-v2__header__cell__sortIcon { + svg:nth-child(2) { + fill: var(--color-gray-60); + } + } + } + + &[aria-sort="descending"] { + .Table-v2__header__cell__sortIcon { + svg:nth-child(1) { + fill: var(--color-gray-60); + } + } + } + } + + td { + font-size: pxToRem(14px); + line-height: pxToRem(22px); + font-weight: var(--font-weight-regular); + color: var(--color-gray-80); + + &[data-text-align="right"] { + text-align: right; + } + + .Table-v2__cell--fixedWidth, + .Table-v2__cell--fixedWidth > * { + display: block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .Table-v2__cell--fixedWidth--allowOverflow, + .Table-v2__cell--fixedWidth--allowOverflow > * { + overflow: visible; + } + } +} diff --git a/src/components/Toast/index.tsx b/src/components/Toast/index.tsx new file mode 100644 index 0000000..880afb3 --- /dev/null +++ b/src/components/Toast/index.tsx @@ -0,0 +1,37 @@ +import { useEffect } from "react"; +import "./styles.scss"; + +interface ToastProps { + children: React.ReactNode; + isVisible: boolean; + setIsVisible: (state: boolean) => void; + delay?: number; +} + +export const Toast: React.FC = ({ + children, + isVisible, + setIsVisible, + delay = 3000, +}: ToastProps) => { + useEffect(() => { + let t: ReturnType; + + if (isVisible) { + t = setTimeout(() => { + setIsVisible(false); + clearTimeout(t); + }, delay); + } + + return () => { + clearTimeout(t); + }; + }, [delay, isVisible, setIsVisible]); + + return ( +
+ {children} +
+ ); +}; diff --git a/src/components/Toast/styles.scss b/src/components/Toast/styles.scss new file mode 100644 index 0000000..8c11d79 --- /dev/null +++ b/src/components/Toast/styles.scss @@ -0,0 +1,3 @@ +.Toast { + transition: opacity var(--anim-transition-default); +} diff --git a/src/components/UserSession.tsx b/src/components/UserSession.tsx new file mode 100644 index 0000000..24cf564 --- /dev/null +++ b/src/components/UserSession.tsx @@ -0,0 +1,86 @@ +import { useEffect } from "react"; +import { useDispatch } from "react-redux"; +import { LOCAL_STORAGE_SESSION_TOKEN } from "constants/settings"; +import { AppDispatch, resetStoreAction } from "store"; +import { setUserInfoAction, restoreUserSession } from "store/ducks/userAccount"; +import { parseJwt } from "helpers/parseJwt"; +import { useRedux } from "hooks/useRedux"; +import { getProfileInfoAction } from "store/ducks/profile"; +import { getOrgInfoAction, getOrgLogoAction } from "store/ducks/organization"; + +export const UserSession = () => { + const { userAccount, profile, organization } = useRedux( + "userAccount", + "profile", + "organization", + ); + const dispatch: AppDispatch = useDispatch(); + + const isSessionExpired = userAccount.isSessionExpired; + + useEffect(() => { + if (userAccount.token) { + if (!profile.data.email) { + dispatch(getProfileInfoAction()); + } + + if (!organization.data.name) { + dispatch(getOrgInfoAction()); + dispatch(getOrgLogoAction()); + } + } + }, [dispatch, organization.data.name, profile.data.email, userAccount.token]); + + useEffect(() => { + return () => { + if (organization.data.logo) { + URL.revokeObjectURL(organization.data.logo); + } + }; + }, [organization.data.logo]); + + useEffect(() => { + if (userAccount.isTokenRefresh) { + // Update refresh token, other info won't change + localStorage.setItem(LOCAL_STORAGE_SESSION_TOKEN, userAccount.token); + } else { + // Set user info on login or page refresh only once + if (userAccount.token && !userAccount.email) { + const parsedToken = parseJwt(userAccount.token); + dispatch(setUserInfoAction(parsedToken.user)); + localStorage.setItem(LOCAL_STORAGE_SESSION_TOKEN, userAccount.token); + } else if ( + // Clear user info on logout + !userAccount.token && + userAccount.status === "SUCCESS" + ) { + dispatch(resetStoreAction()); + localStorage.removeItem(LOCAL_STORAGE_SESSION_TOKEN); + } + } + }, [ + dispatch, + userAccount.email, + userAccount.isTokenRefresh, + userAccount.status, + userAccount.token, + ]); + + useEffect(() => { + // Clear local storage when session expired + if (isSessionExpired) { + dispatch(resetStoreAction()); + localStorage.removeItem(LOCAL_STORAGE_SESSION_TOKEN); + return; + } + + // Start session from saved token + const sessionToken = localStorage.getItem(LOCAL_STORAGE_SESSION_TOKEN); + + if (sessionToken && !isSessionExpired) { + dispatch(restoreUserSession(sessionToken)); + } + }, [dispatch, isSessionExpired]); + + return null; +}; diff --git a/src/components/WalletTrustlines/index.tsx b/src/components/WalletTrustlines/index.tsx new file mode 100644 index 0000000..34863a7 --- /dev/null +++ b/src/components/WalletTrustlines/index.tsx @@ -0,0 +1,450 @@ +import { useEffect, useState } from "react"; +import { + Button, + Card, + Input, + Modal, + Notification, +} from "@stellar/design-system"; +import { useMutation, useQuery } from "@tanstack/react-query"; + +import { getAssets } from "api/getAssets"; +import { postAssets } from "api/postAssets"; +import { deleteAsset } from "api/deleteAsset"; +import { InfoTooltip } from "components/InfoTooltip"; +import { DropdownMenu } from "components/DropdownMenu"; +import { MoreMenuButton } from "components/MoreMenuButton"; +import { NotificationWithButtons } from "components/NotificationWithButtons"; + +import { parseApiError } from "helpers/parseApiError"; +import { useSessionToken } from "hooks/useSessionToken"; +import { ApiError, StellarAccountBalance } from "types"; + +import "./styles.scss"; + +interface WalletTrustlinesProps { + balances?: StellarAccountBalance[]; + onSuccess: () => void; +} + +export const WalletTrustlines = ({ + balances, + onSuccess, +}: WalletTrustlinesProps) => { + type FormItems = { + fassetcode?: string; + fassetissuer?: string; + }; + + const initForm = { + fassetcode: "", + fassetissuer: "", + }; + + type Trustline = { + id: string | null; + code: string; + issuer: string; + balance: string; + isNative: boolean; + }; + + const [isAddModalVisible, setIsAddModalVisible] = useState(false); + const [isRemoveModalVisible, setIsRemoveModalVisible] = useState(false); + const [formItems, setFormItems] = useState(initForm); + const [formError, setFormError] = useState([]); + const [removeAssetId, setRemoveAssetId] = useState(); + const [trustlines, setTrustlines] = useState(); + const [successNotification, setSuccessNotification] = useState< + { title: string; message: string } | undefined + >(); + + const sessionToken = useSessionToken(); + + const ASSET_NAME: { [key: string]: string } = { + XLM: "Stellar Lumens", + USDC: "USD Coin", + EUROC: "EURO Coin", + // SRT is used for testing + SRT: "Stellar Reference Token", + }; + + const getTrustlines = async () => { + if (!balances) { + return []; + } + + return await getAssets(sessionToken); + }; + + const submitAddTrustline = () => { + return postAssets(sessionToken, { + code: formItems.fassetcode!, + issuer: formItems.fassetissuer!, + }); + }; + + const { + isFetching: assetsIsFetching, + data: assets, + isError: assetsIsError, + isSuccess: assetsIsSuccess, + error: assetsError, + refetch: assetsRefetch, + } = useQuery({ + queryKey: ["WalletTrustlinesAssets"], + queryFn: () => (balances ? getTrustlines() : []), + enabled: Boolean(balances), + }); + + useEffect(() => { + if (balances?.length && assetsIsSuccess) { + const test = balances?.map((b) => { + const id = + assets?.find( + (a) => a.code === b?.assetCode && a.issuer === b?.assetIssuer, + )?.id || null; + + return { + id, + code: b?.assetCode || "XLM", + issuer: b?.assetIssuer || "native", + balance: b.balance, + isNative: Boolean(!b.assetCode && !b.assetIssuer), + }; + }); + + setTrustlines(test); + } + }, [assets, assetsIsSuccess, balances]); + + const { + mutate: trustlineAdd, + isLoading: trustlineAddIsLoading, + isError: trustlineAddIsError, + error: trustlineAddError, + reset: trustlineAddReset, + } = useMutation({ + mutationFn: submitAddTrustline, + retry: false, + onSuccess: (addedAsset) => { + handleCloseModal(); + onSuccess(); + assetsRefetch(); + setSuccessNotification({ + title: "Trustline added", + message: `Trustline ${ASSET_NAME[addedAsset.code]} (${ + addedAsset.code + }) was added.`, + }); + }, + }); + + const { + mutate: trustlineRemove, + isLoading: trustlineRemoveIsLoading, + isError: trustlineRemoveIsError, + error: trustlineRemoveError, + reset: trustlineRemoveReset, + } = useMutation({ + mutationFn: () => deleteAsset(sessionToken, removeAssetId!), + retry: false, + onSuccess: (removeAsset) => { + handleCloseModal(); + onSuccess(); + assetsRefetch(); + setSuccessNotification({ + title: "Trustline removed", + message: `Trustline ${ASSET_NAME[removeAsset.code]} (${ + removeAsset.code + }) was removed.`, + }); + }, + }); + + const handleCloseModal = () => { + setIsAddModalVisible(false); + setIsRemoveModalVisible(false); + setFormItems(initForm); + setFormError([]); + setRemoveAssetId(undefined); + + if (trustlineAddIsError) { + trustlineAddReset(); + } + + if (trustlineRemoveIsError) { + trustlineRemoveReset(); + } + }; + + const filledItems = () => Object.values(formItems).filter((v) => v); + + const canSubmit = formError.length === 0 && filledItems().length === 2; + + const removeItemFromErrors = (id: string) => { + setFormError(formError.filter((e) => e !== id)); + }; + + const handleChange = ( + event: + | React.ChangeEvent + | React.ChangeEvent, + ) => { + removeItemFromErrors(event.target.id); + setFormItems({ + ...formItems, + [event.target.id]: event.target.value, + }); + + if (trustlineAddIsError) { + trustlineAddReset(); + } + }; + + const handleValidate = ( + event: + | React.ChangeEvent + | React.ChangeEvent, + ) => { + if (!event.target.value) { + if (!formError.includes(event.target.value)) { + setFormError([...formError, event.target.id]); + } + } + }; + + const itemHasError = (id: string, label: string) => { + return formError.includes(id) ? `${label} is required` : undefined; + }; + + const renderContent = () => { + if (assetsIsFetching) { + return
Loading…
; + } + + if (trustlines?.length === 0) { + return
There are no trustlines
; + } + + return ( + <> + {trustlines?.map((a) => { + const isRemoveEnabled = Number(a.balance) === 0; + + return ( +
+
+
{ASSET_NAME?.[a.code] || ""}
+ {a.code} +
+ + {!a.isNative && a.id ? ( + }> + { + if (isRemoveEnabled) { + setIsRemoveModalVisible(true); + setRemoveAssetId(a.id!); + } + }} + isHighlight + aria-disabled={!isRemoveEnabled} + title={ + !isRemoveEnabled + ? "You can only remove an asset when the asset balance is 0" + : "" + } + > + Remove trustline + + + ) : null} +
+ ); + })} + +
+ +
+ + ); + }; + + const getRemoveAssetConfirmation = () => { + const asset = assets?.find((a) => a.id === removeAssetId); + + if (asset) { + return `Are you sure you want to remove ${ + ASSET_NAME[asset.code] ?? asset.code + }?`; + } + + return "Something went wrong, the asset was not found."; + }; + + return ( + <> + {assetsIsError ? ( + + {assetsError as string} + + ) : null} + + {successNotification ? ( + { + setSuccessNotification(undefined); + trustlineAddReset(); + trustlineRemoveReset(); + }, + }, + ]} + > + {successNotification.message} + + ) : null} + + +
+
+ + Trustlines + +
+ + {renderContent()} +
+
+ + {/* Add asset modal */} + + Add trustline +
{ + event.preventDefault(); + trustlineAdd(); + }} + onReset={handleCloseModal} + > + + {trustlineAddIsError ? ( + + {parseApiError(trustlineAddError as ApiError)} + + ) : null} + + + Asset code + + } + value={formItems.fassetcode} + onChange={handleChange} + onBlur={handleValidate} + error={itemHasError("fassetcode", "Asset code")} + /> + + Issuer public key + + } + value={formItems.fassetissuer} + onChange={handleChange} + onBlur={handleValidate} + error={itemHasError("fassetissuer", "Issuer public key")} + /> + + + + + +
+
+ + {/* Remove asset modal */} + + Remove trustline +
{ + event.preventDefault(); + trustlineRemove(); + }} + onReset={handleCloseModal} + > + + {trustlineRemoveIsError ? ( + + {parseApiError(trustlineRemoveError as ApiError)} + + ) : null} + +
{getRemoveAssetConfirmation()}
+
+ + + + +
+
+ + ); +}; diff --git a/src/components/WalletTrustlines/styles.scss b/src/components/WalletTrustlines/styles.scss new file mode 100644 index 0000000..57c9686 --- /dev/null +++ b/src/components/WalletTrustlines/styles.scss @@ -0,0 +1,33 @@ +@use "./styles-utils.scss" as *; + +.WalletTrustlines { + &__asset { + display: flex; + align-items: center; + justify-content: space-between; + gap: pxToRem(16px); + border: 1px solid var(--color-gray-30); + border-radius: pxToRem(4px); + background-color: var(--color-gray-00); + padding: pxToRem(6px) pxToRem(10px); + + &__info { + display: flex; + gap: pxToRem(8px); + align-items: center; + font-size: pxToRem(14px); + line-height: pxToRem(22px); + font-weight: var(--font-weight-regular); + color: var(--color-gray-80); + + span { + color: var(--color-gray-60); + } + } + } + + &__button { + display: flex; + justify-content: flex-end; + } +} diff --git a/src/constants/settings.ts b/src/constants/settings.ts new file mode 100644 index 0000000..9cf9628 --- /dev/null +++ b/src/constants/settings.ts @@ -0,0 +1,204 @@ +import { UserRole } from "types"; + +export const PROJECT_NAME = "stellarDisbursementPlatform"; +export const LOCALE = "en-US"; +export const RESET_STORE_ACTION_TYPE = "RESET"; +export const API_URL = window._env_.API_URL; +export const STELLAR_EXPERT_URL = window._env_.STELLAR_EXPERT_URL; +export const HORIZON_URL = window._env_.HORIZON_URL; +export const RECAPTCHA_SITE_KEY = window._env_.RECAPTCHA_SITE_KEY; + +export const USE_SSO = window._env_.USE_SSO; +export const OIDC_AUTHORITY = window._env_.OIDC_AUTHORITY; +export const OIDC_CLIENT_ID = window._env_.OIDC_CLIENT_ID; +export const OIDC_REDIRECT_URI = window._env_.OIDC_REDIRECT_URI; +export const OIDC_SCOPE = window._env_.OIDC_SCOPE; +export const OIDC_USERNAME_MAPPING = window._env_.OIDC_USERNAME_MAPPING; + +export const GENERIC_ERROR_MESSAGE = "Something went wrong, please try again"; +export const SESSION_EXPIRED = "SESSION EXPIRED"; +export const LOCAL_STORAGE_SESSION_TOKEN = "sdp_session"; +export const LOCAL_STORAGE_DEVICE_ID = "sdp_deviceID"; +export const UI_STATUS_DISBURSEMENT = "STARTED,PAUSED,COMPLETED"; +export const UI_STATUS_DISBURSEMENT_DRAFT = "DRAFT,READY"; + +export enum Routes { + MFA = "/mfa", + HOME = "/home", + FORGOT_PASSWORD = "/forgot-password", + RESET_PASSWORD = "/reset-password", + DISBURSEMENTS = "/disbursements", + DISBURSEMENT_NEW = "/disbursements/new", + DISBURSEMENT_DRAFTS = "/disbursements/drafts", + RECEIVERS = "/receivers", + PAYMENTS = "/payments", + WALLETS = "/wallets", + ANALYTICS = "/analytics", + PROFILE = "/profile", + SETTINGS = "/settings", + HELP = "/help", + UNAUTHORIZED = "/unauthorized", +} + +export const PAGE_LIMIT_OPTIONS = [20, 50, 100]; +export const USER_ROLES_ARRAY: UserRole[] = [ + "owner", + "financial_controller", + "developer", + "business", +]; + +export const TIME_ZONES = [ + { + name: "GMT -12:00", + value: "-12:00", + }, + { + name: "GMT -11:00", + value: "-11:00", + }, + { + name: "GMT -10:00", + value: "-10:00", + }, + { + name: "GMT -09:30", + value: "-09:30", + }, + { + name: "GMT -09:00", + value: "-09:00", + }, + { + name: "GMT -08:00", + value: "-08:00", + }, + { + name: "GMT -07:00", + value: "-07:00", + }, + { + name: "GMT -06:00", + value: "-06:00", + }, + { + name: "GMT -05:00", + value: "-05:00", + }, + { + name: "GMT -04:00", + value: "-04:00", + }, + { + name: "GMT -03:30", + value: "-03:30", + }, + { + name: "GMT -03:00", + value: "-03:00", + }, + { + name: "GMT -02:00", + value: "-02:00", + }, + { + name: "GMT -01:00", + value: "-01:00", + }, + { + name: "GMT +00:00", + value: "+00:00", + }, + { + name: "GMT +01:00", + value: "+01:00", + }, + { + name: "GMT +02:00", + value: "+02:00", + }, + { + name: "GMT +03:00", + value: "+03:00", + }, + { + name: "GMT +03:30", + value: "+03:30", + }, + { + name: "GMT +04:00", + value: "+04:00", + }, + { + name: "GMT +04:30", + value: "+04:30", + }, + { + name: "GMT +05:00", + value: "+05:00", + }, + { + name: "GMT +05:30", + value: "+05:30", + }, + { + name: "GMT +05:45", + value: "+05:45", + }, + { + name: "GMT +06:00", + value: "+06:00", + }, + { + name: "GMT +06:30", + value: "+06:30", + }, + { + name: "GMT +07:00", + value: "+07:00", + }, + { + name: "GMT +08:00", + value: "+08:00", + }, + { + name: "GMT +08:45", + value: "+08:45", + }, + { + name: "GMT +09:00", + value: "+09:00", + }, + { + name: "GMT +09:30", + value: "+09:30", + }, + { + name: "GMT +10:00", + value: "+10:00", + }, + { + name: "GMT +10:30", + value: "+10:30", + }, + { + name: "GMT +11:00", + value: "+11:00", + }, + { + name: "GMT +12:00", + value: "+12:00", + }, + { + name: "GMT +12:45", + value: "+12:45", + }, + { + name: "GMT +13:00", + value: "+13:00", + }, + { + name: "GMT +14:00", + value: "+14:00", + }, +]; diff --git a/src/generated/gitInfo.ts b/src/generated/gitInfo.ts new file mode 100644 index 0000000..e3eacf8 --- /dev/null +++ b/src/generated/gitInfo.ts @@ -0,0 +1 @@ +export default { commitHash: "b6fa31e" }; diff --git a/src/helpers/capitalizeString.ts b/src/helpers/capitalizeString.ts new file mode 100644 index 0000000..4f0c8c1 --- /dev/null +++ b/src/helpers/capitalizeString.ts @@ -0,0 +1,2 @@ +export const capitalizeString = (text: string) => + (text && text[0].toUpperCase() + text.slice(1)) || text; diff --git a/src/helpers/createUrlSearchParamsString.ts b/src/helpers/createUrlSearchParamsString.ts new file mode 100644 index 0000000..5929637 --- /dev/null +++ b/src/helpers/createUrlSearchParamsString.ts @@ -0,0 +1,11 @@ +export const createUrlSearchParamsString = >( + params: T, +) => { + const searchParams = new URLSearchParams(); + + Object.entries(params).forEach(([key, value]) => { + searchParams.append(key, value); + }); + + return `?${searchParams.toString()}`; +}; diff --git a/src/helpers/endSessionIfTokenInvalid.ts b/src/helpers/endSessionIfTokenInvalid.ts new file mode 100644 index 0000000..8508c2d --- /dev/null +++ b/src/helpers/endSessionIfTokenInvalid.ts @@ -0,0 +1,13 @@ +import { sessionExpiredAction } from "store/ducks/userAccount"; +import { SESSION_EXPIRED, USE_SSO } from "constants/settings"; +import { singleUserStore } from "helpers/singleSingOn"; + +export const endSessionIfTokenInvalid = (error: string, dispatch: any) => { + if (error === SESSION_EXPIRED) { + if (USE_SSO) { + // reset user store (from session storage) + singleUserStore().then(); + } + dispatch(sessionExpiredAction()); + } +}; diff --git a/src/helpers/formatDisbursements.ts b/src/helpers/formatDisbursements.ts new file mode 100644 index 0000000..83c8d4e --- /dev/null +++ b/src/helpers/formatDisbursements.ts @@ -0,0 +1,38 @@ +import { ApiDisbursement, Disbursement } from "types"; + +export const formatDisbursements = ( + disbursements: ApiDisbursement[], +): Disbursement[] => { + return disbursements.map((d) => formatDisbursement(d)); +}; + +export const formatDisbursement = ( + disbursement: ApiDisbursement, +): Disbursement => ({ + id: disbursement.id, + name: disbursement.name, + createdAt: disbursement.created_at, + stats: { + paymentsSuccessfulCount: disbursement.total_payments_sent, + paymentsFailedCount: disbursement.total_payments_failed, + paymentsRemainingCount: disbursement.total_payments_remaining, + paymentsTotalCount: disbursement.total_payments, + totalAmount: disbursement.total_amount, + disbursedAmount: disbursement.amount_disbursed, + averagePaymentAmount: disbursement.average_amount, + }, + status: disbursement.status, + country: { + name: disbursement.country.name, + code: disbursement.country.code, + }, + asset: { + id: disbursement.asset.id, + code: disbursement.asset.code, + }, + wallet: { + id: disbursement.wallet.id, + name: disbursement.wallet.name, + }, + fileName: disbursement.file_name, +}); diff --git a/src/helpers/formatIntlDateTime.ts b/src/helpers/formatIntlDateTime.ts new file mode 100644 index 0000000..4d41c9d --- /dev/null +++ b/src/helpers/formatIntlDateTime.ts @@ -0,0 +1,27 @@ +// TODO: customize locale +export const formatDateTimeWithGmt = (dateTime?: string) => { + const date = dateTime ? new Date(dateTime) : new Date(); + const dateTimeFormatter = new Intl.DateTimeFormat("en-US", { + month: "short", + day: "numeric", + year: "numeric", + hour: "numeric", + minute: "2-digit", + timeZoneName: "shortOffset", + }); + + return dateTimeFormatter.format(date); +}; + +export const formatDateTime = (dateTime?: string) => { + const date = dateTime ? new Date(dateTime) : new Date(); + const dateTimeFormatter = new Intl.DateTimeFormat("en-US", { + month: "short", + day: "numeric", + year: "numeric", + hour: "numeric", + minute: "2-digit", + }); + + return dateTimeFormatter.format(date); +}; diff --git a/src/helpers/formatIntlNumber.ts b/src/helpers/formatIntlNumber.ts new file mode 100644 index 0000000..eac6708 --- /dev/null +++ b/src/helpers/formatIntlNumber.ts @@ -0,0 +1,20 @@ +import { LOCALE } from "constants/settings"; + +export const currency = new Intl.NumberFormat(LOCALE, { + style: "currency", + currency: "USD", +}); + +export const decimal = new Intl.NumberFormat(LOCALE, { + style: "decimal", + minimumFractionDigits: 2, + maximumFractionDigits: 2, +}); + +export const percent = new Intl.NumberFormat(LOCALE, { + style: "percent", + minimumFractionDigits: 2, + maximumFractionDigits: 2, +}); + +export const number = new Intl.NumberFormat(LOCALE); diff --git a/src/helpers/formatReceivers.ts b/src/helpers/formatReceivers.ts new file mode 100644 index 0000000..07c10b7 --- /dev/null +++ b/src/helpers/formatReceivers.ts @@ -0,0 +1,18 @@ +import { ApiReceiver, Receiver } from "types"; + +export const formatReceivers = (receivers: ApiReceiver[]): Receiver[] => { + return receivers.map((r) => ({ + id: r.id, + phoneNumber: r.phone_number, + walletProvider: r.wallets.map((w) => w.wallet.name), + walletsRegisteredCount: Number(r.registered_wallets), + totalPaymentsCount: Number(r.total_payments), + successfulPaymentsCounts: Number(r.successful_payments), + createdAt: r.created_at, + amountsReceived: r.received_amounts.map((a) => ({ + assetCode: a.asset_code, + assetIssuer: a.asset_issuer, + amount: a.received_amount, + })), + })); +}; diff --git a/src/helpers/formatUkrainianPhoneNumber.ts b/src/helpers/formatUkrainianPhoneNumber.ts new file mode 100644 index 0000000..fc9ff72 --- /dev/null +++ b/src/helpers/formatUkrainianPhoneNumber.ts @@ -0,0 +1,14 @@ +export const formatUkrainianPhoneNumber = (phoneNumber: string) => { + const sanitizedNumber = phoneNumber?.trim(); + // +380 44 xxx-xx-xx + if (sanitizedNumber.startsWith("+380") && sanitizedNumber.length === 13) { + const match = sanitizedNumber.match( + /^(\+380)(\d{2})(\d{3})(\d{2})(\d{2})$/s, + ); + if (match) { + return `${match[1]} ${match[2]} ${match[3]}-${match[4]}-${match[5]}`; + } + } + + return sanitizedNumber; +}; diff --git a/src/helpers/formatUploadedFileDisplayName.tsx b/src/helpers/formatUploadedFileDisplayName.tsx new file mode 100644 index 0000000..d989ef2 --- /dev/null +++ b/src/helpers/formatUploadedFileDisplayName.tsx @@ -0,0 +1,15 @@ +export const formatUploadedFileDisplayName = (file: File) => { + return `${file.name} (${formatSize(file.size)})`; +}; + +const formatSize = (bytesSize: number): string => { + if (bytesSize < 1024) { + return `${bytesSize} bytes`; + } else if (bytesSize >= 1024 && bytesSize < 1048576) { + return `${(bytesSize / 1024).toFixed(2)} KB`; + } else if (bytesSize >= 1048576) { + return `${(bytesSize / 1048576).toFixed(2)} MB`; + } else { + return ""; + } +}; diff --git a/src/helpers/getAppVersion.ts b/src/helpers/getAppVersion.ts new file mode 100644 index 0000000..af3c45a --- /dev/null +++ b/src/helpers/getAppVersion.ts @@ -0,0 +1,3 @@ +import PackageJson from "../../package.json"; + +export const getAppVersion = () => PackageJson.version; diff --git a/src/helpers/getCurrentPageItems.ts b/src/helpers/getCurrentPageItems.ts new file mode 100644 index 0000000..0b6decf --- /dev/null +++ b/src/helpers/getCurrentPageItems.ts @@ -0,0 +1,28 @@ +type GetCurrentPageItemsProps = { + currentIndex: number | undefined; + allItems: T[]; + maxCount: number; + pageSize: number; + onFetchMore: () => void; +}; + +export const getCurrentPageItems = ({ + currentIndex = 1, + allItems, + maxCount, + pageSize, + onFetchMore, +}: GetCurrentPageItemsProps) => { + const index = currentIndex - 1; + const currentSize = allItems.length; + const startAt = index * pageSize; + const endAt = Math.min(maxCount, startAt + pageSize); + + // Have all items to show + if (currentSize >= endAt) { + return allItems.slice(startAt, endAt); + } + + onFetchMore(); + return null; +}; diff --git a/src/helpers/getInstructionsFile.ts b/src/helpers/getInstructionsFile.ts new file mode 100644 index 0000000..8746b6b --- /dev/null +++ b/src/helpers/getInstructionsFile.ts @@ -0,0 +1,17 @@ +import { getDisbursementInstructions } from "api/getDisbursementInstructions"; + +export const getInstructionsFile = async ({ + token, + disbursementId, + fileName, +}: { + token: string; + disbursementId: string; + fileName: string; +}): Promise => { + const file = await getDisbursementInstructions(token, disbursementId); + + return new File([file], fileName, { + type: file.type, + }); +}; diff --git a/src/helpers/getPluralizedText.ts b/src/helpers/getPluralizedText.ts new file mode 100644 index 0000000..def72ce --- /dev/null +++ b/src/helpers/getPluralizedText.ts @@ -0,0 +1,25 @@ +import { capitalizeString } from "helpers/capitalizeString"; + +export const getPluralizedText = ({ + count, + singular, + plural, +}: { + count: number; + singular: string; + plural: string; +}) => { + if (count === 0) { + return capitalizeString(plural); + } + + if (count === 1) { + return `1 ${singular}`; + } + + if (count > 1) { + return `${count} ${plural}`; + } + + return ""; +}; diff --git a/src/helpers/parseApiError.ts b/src/helpers/parseApiError.ts new file mode 100644 index 0000000..5293128 --- /dev/null +++ b/src/helpers/parseApiError.ts @@ -0,0 +1,14 @@ +import { ApiError } from "types"; + +export const parseApiError = (error: ApiError) => { + const errorMessage = error.error; + const errorExtras = error.extras + ? Object.values(error.extras).join(", ") + : ""; + + if (errorExtras) { + return `${errorMessage}: ${errorExtras}`; + } + + return `${errorMessage}`; +}; diff --git a/src/helpers/parseJwt.ts b/src/helpers/parseJwt.ts new file mode 100644 index 0000000..e62d74e --- /dev/null +++ b/src/helpers/parseJwt.ts @@ -0,0 +1,11 @@ +import { Buffer } from "buffer"; + +export const parseJwt = (token: string) => { + try { + const base64Payload = token.split(".")[1]; + const payload = Buffer.from(base64Payload, "base64"); + return JSON.parse(payload.toString()); + } catch (e) { + return {}; + } +}; diff --git a/src/helpers/refreshSessionToken.ts b/src/helpers/refreshSessionToken.ts new file mode 100644 index 0000000..78541a2 --- /dev/null +++ b/src/helpers/refreshSessionToken.ts @@ -0,0 +1,5 @@ +import { refreshTokenAction } from "store/ducks/userAccount"; + +export const refreshSessionToken = (dispatch: any) => { + dispatch(refreshTokenAction()); +}; diff --git a/src/helpers/removeFalsyKeys.ts b/src/helpers/removeFalsyKeys.ts new file mode 100644 index 0000000..44d045f --- /dev/null +++ b/src/helpers/removeFalsyKeys.ts @@ -0,0 +1,10 @@ +import { AnyObject } from "types"; + +export const removeFalsyKeys = (obj: AnyObject): AnyObject => + Object.keys(obj).reduce((res, cur) => { + if (obj[cur]) { + return { ...res, [cur]: obj[cur] }; + } + + return res; + }, {}); diff --git a/src/helpers/renderNumberOrDash.ts b/src/helpers/renderNumberOrDash.ts new file mode 100644 index 0000000..eef5298 --- /dev/null +++ b/src/helpers/renderNumberOrDash.ts @@ -0,0 +1,9 @@ +import { number as formatNumber } from "helpers/formatIntlNumber"; + +export const renderNumberOrDash = (number?: number) => { + if (number !== undefined && number !== null) { + return formatNumber.format(number); + } + + return "-"; +}; diff --git a/src/helpers/sanitizeObject.ts b/src/helpers/sanitizeObject.ts new file mode 100644 index 0000000..0e450db --- /dev/null +++ b/src/helpers/sanitizeObject.ts @@ -0,0 +1,6 @@ +import { AnyObject } from "types"; + +export const sanitizeObject = (object: AnyObject) => + Object.entries(object) + .filter(([, val]) => Boolean(val)) + .reduce((obj, [key, val]) => ({ ...obj, [key]: val }), {}); diff --git a/src/helpers/saveFile.ts b/src/helpers/saveFile.ts new file mode 100644 index 0000000..584fa39 --- /dev/null +++ b/src/helpers/saveFile.ts @@ -0,0 +1,37 @@ +export const saveFile = ({ + file, + fileUrl, + suggestedFileName, + callback, + delay, +}: { + file?: File; + fileUrl?: string; + suggestedFileName: string; + callback?: () => void; + delay?: number; +}) => { + const objUrl = file ? URL.createObjectURL(file) : fileUrl; + const a = document.createElement("a"); + + if (!objUrl) { + throw Error("Either file or fileUrl is required"); + } + + a.href = objUrl; + a.download = suggestedFileName; + a.style.display = "none"; + + document.body.append(a); + a.click(); + + const t = setTimeout(() => { + URL.revokeObjectURL(objUrl); + a.remove(); + + if (callback) { + callback(); + } + clearTimeout(t); + }, delay ?? 3000); +}; diff --git a/src/helpers/shortenAccountKey.ts b/src/helpers/shortenAccountKey.ts new file mode 100644 index 0000000..722ef4c --- /dev/null +++ b/src/helpers/shortenAccountKey.ts @@ -0,0 +1,2 @@ +export const shortenAccountKey = (accountKey: string) => + `${accountKey.slice(0, 5)}…${accountKey.slice(-5)}`; diff --git a/src/helpers/shortenString.ts b/src/helpers/shortenString.ts new file mode 100644 index 0000000..3afe3fd --- /dev/null +++ b/src/helpers/shortenString.ts @@ -0,0 +1,4 @@ +export const shortenString = (text: string, buffer?: number) => { + const bufferSize = buffer || 5; + return `${text.slice(0, bufferSize)}…${text.slice(-bufferSize)}`; +}; diff --git a/src/helpers/singleSingOn.ts b/src/helpers/singleSingOn.ts new file mode 100644 index 0000000..ec65527 --- /dev/null +++ b/src/helpers/singleSingOn.ts @@ -0,0 +1,29 @@ +import { User, UserManager } from "oidc-client-ts"; +import { + OIDC_AUTHORITY, + OIDC_CLIENT_ID, + OIDC_REDIRECT_URI, + OIDC_SCOPE, +} from "constants/settings"; + +const config = { + authority: OIDC_AUTHORITY, + client_id: OIDC_CLIENT_ID, + redirect_uri: OIDC_REDIRECT_URI, + scope: OIDC_SCOPE, + automaticSilentRenew: false, +}; + +const userManager = new UserManager(config); + +export async function signInRedirect() { + await userManager.signinRedirect(); +} + +export function signInRedirectCallback() { + return userManager.signinRedirectCallback(); +} + +export async function singleUserStore(user: User | null = null) { + await userManager.storeUser(user); +} diff --git a/src/helpers/userRoleText.ts b/src/helpers/userRoleText.ts new file mode 100644 index 0000000..c7424cc --- /dev/null +++ b/src/helpers/userRoleText.ts @@ -0,0 +1,16 @@ +import { UserRole } from "types"; + +export const userRoleText = (role?: UserRole | null) => { + switch (role) { + case "owner": + return "Owner"; + case "business": + return "Business user"; + case "developer": + return "Developer"; + case "financial_controller": + return "Financial controller"; + default: + return ""; + } +}; diff --git a/src/hooks/useDownloadCsvFile.ts b/src/hooks/useDownloadCsvFile.ts new file mode 100644 index 0000000..55fe22d --- /dev/null +++ b/src/hooks/useDownloadCsvFile.ts @@ -0,0 +1,46 @@ +import { useCallback, useEffect, useState } from "react"; +import { useRedux } from "hooks/useRedux"; +import { getInstructionsFile } from "helpers/getInstructionsFile"; + +export const useDownloadCsvFile = ( + callback: (file: File) => void, + enableUseEffect?: boolean, +) => { + const { userAccount, disbursementDetails } = useRedux( + "userAccount", + "disbursementDetails", + ); + const [isLoading, setIsLoading] = useState(false); + + const getFile = useCallback(async () => { + if ( + disbursementDetails.details.fileName && + disbursementDetails.details.id && + userAccount.token + ) { + setIsLoading(true); + + const file = await getInstructionsFile({ + token: userAccount.token, + disbursementId: disbursementDetails.details.id, + fileName: disbursementDetails.details.fileName, + }); + + callback(file); + setIsLoading(false); + } + }, [ + callback, + disbursementDetails.details.fileName, + disbursementDetails.details.id, + userAccount.token, + ]); + + useEffect(() => { + if (enableUseEffect && disbursementDetails.details.fileName) { + getFile(); + } + }, [enableUseEffect, disbursementDetails.details.fileName, getFile]); + + return { isLoading, getFile }; +}; diff --git a/src/hooks/useIsUserRoleAccepted.ts b/src/hooks/useIsUserRoleAccepted.ts new file mode 100644 index 0000000..cd5a3d3 --- /dev/null +++ b/src/hooks/useIsUserRoleAccepted.ts @@ -0,0 +1,10 @@ +import { useRedux } from "hooks/useRedux"; +import { UserRole } from "types"; + +export const useIsUserRoleAccepted = (acceptedRoles: UserRole[]) => { + const { userAccount } = useRedux("userAccount"); + return { + isRoleAccepted: + userAccount.role && acceptedRoles.includes(userAccount.role), + }; +}; diff --git a/src/hooks/useOrgAccountInfo.ts b/src/hooks/useOrgAccountInfo.ts new file mode 100644 index 0000000..b6a5e0b --- /dev/null +++ b/src/hooks/useOrgAccountInfo.ts @@ -0,0 +1,16 @@ +import { useEffect } from "react"; +import { useDispatch } from "react-redux"; +import { AppDispatch } from "store"; +import { getStellarAccountAction } from "store/ducks/organization"; + +export const useOrgAccountInfo = ( + distributionAccountPublicKey: string | undefined, +) => { + const dispatch: AppDispatch = useDispatch(); + + useEffect(() => { + if (distributionAccountPublicKey) { + dispatch(getStellarAccountAction(distributionAccountPublicKey)); + } + }, [dispatch, distributionAccountPublicKey]); +}; diff --git a/src/hooks/useRedux.ts b/src/hooks/useRedux.ts new file mode 100644 index 0000000..85c2b43 --- /dev/null +++ b/src/hooks/useRedux.ts @@ -0,0 +1,30 @@ +import isEqual from "lodash/isEqual"; +import pick from "lodash/pick"; +import { useSelector } from "react-redux"; + +import { Store, StoreKey } from "types"; + +/** + * A React hook for accessing Redux state. + * + * react-redux's useStore hook isn't performant, has a weird call signature, + * and doesn't instruct components when to update: + * + * const { stellarAccount } = useStore().getState(); + * + * useSelector is stupidly verbose: + * + * const { + * stellarAccount + * } = useSelector(({ stellarAccount }) => ({ stellarAccount })); + * + * So instead, let's use a clearer API: + * + * const { stellarAccount } = useRedux("stellarAccount"); + * + * @param {string[]} stateProps An array of prop names to get from the state. + * @returns {object} An object map of those prop names to their values. + */ +export function useRedux(...keys: StoreKey[]) { + return useSelector((state: Store) => pick(state, keys), isEqual); +} diff --git a/src/hooks/useScrollToTop.ts b/src/hooks/useScrollToTop.ts new file mode 100644 index 0000000..ae42705 --- /dev/null +++ b/src/hooks/useScrollToTop.ts @@ -0,0 +1,11 @@ +import { useEffect } from "react"; + +export const useScrollToTop = () => { + useEffect(() => { + window.scrollTo({ + top: 0, + left: 0, + behavior: "smooth", + }); + }, []); +}; diff --git a/src/hooks/useSessionToken.ts b/src/hooks/useSessionToken.ts new file mode 100644 index 0000000..22d8950 --- /dev/null +++ b/src/hooks/useSessionToken.ts @@ -0,0 +1,6 @@ +import { useRedux } from "hooks/useRedux"; + +export const useSessionToken = () => { + const { userAccount } = useRedux("userAccount"); + return userAccount.token; +}; diff --git a/src/hooks/useSort.ts b/src/hooks/useSort.ts new file mode 100644 index 0000000..49290ab --- /dev/null +++ b/src/hooks/useSort.ts @@ -0,0 +1,39 @@ +import { useState } from "react"; +import { SortDirection } from "types"; + +export const useSort = ( + onSort?: (sort?: T, direction?: SortDirection) => void, +) => { + const [sortBy, setSortBy] = useState(); + const [sortDir, setSortDir] = useState( + onSort ? "default" : undefined, + ); + + const handleSort = (id: T) => { + let _sortDir: SortDirection; + + // Sorting by new id + if (sortBy && id !== sortBy) { + _sortDir = "asc"; + } else { + // Sorting the same id + if (sortDir === "default") { + _sortDir = "asc"; + } else if (sortDir === "asc") { + _sortDir = "desc"; + } else { + // from descending + _sortDir = "default"; + } + } + + setSortDir(_sortDir); + setSortBy(id); + + if (onSort) { + onSort(id, _sortDir); + } + }; + + return { handleSort, sortBy, sortDir }; +}; diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..8432fa8 --- /dev/null +++ b/src/index.html @@ -0,0 +1,18 @@ + + + + + + + + + + + Stellar Disbursement Platform + + + + +
+ + diff --git a/src/index.tsx b/src/index.tsx new file mode 100644 index 0000000..06c750a --- /dev/null +++ b/src/index.tsx @@ -0,0 +1,15 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import { App } from "./App"; + +// Import global CSS from Stellar Design System +import "@stellar/design-system/build/styles.min.css"; + +const root = ReactDOM.createRoot( + document.getElementById("root") as HTMLElement, +); +root.render( + + + , +); diff --git a/src/pages/Analytics.tsx b/src/pages/Analytics.tsx new file mode 100644 index 0000000..721cb64 --- /dev/null +++ b/src/pages/Analytics.tsx @@ -0,0 +1,21 @@ +import { Heading } from "@stellar/design-system"; +import { DashboardAnalytics } from "components/DashboardAnalytics"; +import { SectionHeader } from "components/SectionHeader"; + +export const Analytics = () => { + return ( + <> + + + + + Analytics + + + + + + + + ); +}; diff --git a/src/pages/DisbursementDetails.tsx b/src/pages/DisbursementDetails.tsx new file mode 100644 index 0000000..660cfef --- /dev/null +++ b/src/pages/DisbursementDetails.tsx @@ -0,0 +1,609 @@ +import { useCallback, useEffect, useState } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { + Button, + Card, + Heading, + Icon, + Notification, + Select, + Link, + Modal, +} from "@stellar/design-system"; +import { useDispatch } from "react-redux"; + +import { AppDispatch } from "store"; +import { + getDisbursementDetailsAction, + getDisbursementReceiversAction, + pauseOrStartDisbursementAction, + setDisbursementDetailsAction, +} from "store/ducks/disbursementDetails"; +import { useRedux } from "hooks/useRedux"; +import { + PAGE_LIMIT_OPTIONS, + Routes, + STELLAR_EXPERT_URL, +} from "constants/settings"; + +import { Breadcrumbs } from "components/Breadcrumbs"; +import { SectionHeader } from "components/SectionHeader"; +import { CopyWithIcon } from "components/CopyWithIcon"; +import { formatDateTime } from "helpers/formatIntlDateTime"; +import { AssetAmount } from "components/AssetAmount"; +import { Pagination } from "components/Pagination"; +import { Table } from "components/Table"; +import { renderNumberOrDash } from "helpers/renderNumberOrDash"; +import { number } from "helpers/formatIntlNumber"; +import { PaymentStatus } from "components/PaymentStatus"; +import { saveFile } from "helpers/saveFile"; +import { useDownloadCsvFile } from "hooks/useDownloadCsvFile"; + +export const DisbursementDetails = () => { + const { id: disbursementId } = useParams(); + + const { disbursements, disbursementDetails } = useRedux( + "disbursements", + "disbursementDetails", + ); + + const [currentPage, setCurrentPage] = useState(1); + const [pageLimit, setPageLimit] = useState(20); + const [isModalVisible, setIsModalVisible] = useState(false); + + const dispatch: AppDispatch = useDispatch(); + const navigate = useNavigate(); + const { isLoading: csvDownloadIsLoading, getFile } = useDownloadCsvFile( + (file: File) => { + saveFile({ + file, + suggestedFileName: disbursementDetails.details.fileName || "", + }); + }, + ); + + const fetchedDisbursement = disbursements.items.find( + (p) => p.id === disbursementId, + ); + + const maxPages = + disbursementDetails.details.receivers?.pagination?.pages || 1; + const isPaused = disbursementDetails.details.status === "PAUSED"; + + const saveDisbursementDetails = useCallback(() => { + if (fetchedDisbursement) { + dispatch( + setDisbursementDetailsAction({ + details: fetchedDisbursement, + instructions: { + csvFile: undefined, + csvName: undefined, + }, + }), + ); + } + }, [dispatch, fetchedDisbursement]); + + useEffect(() => { + if (fetchedDisbursement?.id) { + saveDisbursementDetails(); + } else if (disbursementId) { + dispatch(getDisbursementDetailsAction(disbursementId)); + } + }, [ + disbursementId, + dispatch, + fetchedDisbursement?.id, + saveDisbursementDetails, + ]); + + useEffect(() => { + if (disbursementDetails.details.id) { + dispatch(getDisbursementReceiversAction()); + } + }, [disbursementDetails.details.id, dispatch]); + + const handleDownloadFile = async ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + getFile(); + }; + + const handlePageLimitChange = ( + event: React.ChangeEvent, + ) => { + event.preventDefault(); + + const pageLimit = Number(event.target.value); + setPageLimit(pageLimit); + setCurrentPage(1); + + // Need to make sure we'll be loading page 1 + dispatch( + getDisbursementReceiversAction({ + page_limit: pageLimit.toString(), + page: "1", + }), + ); + }; + + const handlePageChange = (currentPage: number) => { + dispatch(getDisbursementReceiversAction({ page: currentPage.toString() })); + }; + + const handleNextPage = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + const newPage = currentPage + 1; + + setCurrentPage(newPage); + handlePageChange(newPage); + }; + + const handlePrevPage = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + const newPage = currentPage - 1; + + setCurrentPage(newPage); + handlePageChange(newPage); + }; + + const goToReceiver = ( + event: React.MouseEvent, + receiverId: string, + ) => { + event.preventDefault(); + navigate(`${Routes.RECEIVERS}/${receiverId}`); + }; + + const showModal = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + setIsModalVisible(true); + }; + + const hideModal = ( + event?: React.MouseEvent, + ) => { + event?.preventDefault(); + setIsModalVisible(false); + }; + + const handlePauseOrRestart = ( + event: React.MouseEvent, + status: "PAUSED" | "STARTED", + ) => { + event.preventDefault(); + dispatch(pauseOrStartDisbursementAction(status)); + setIsModalVisible(false); + }; + + const renderStatCards = () => { + return ( +
+ +
+
+ +
+ {renderNumberOrDash( + disbursementDetails.details.stats?.paymentsTotalCount, + )} +
+
+ +
+ +
+ {formatDateTime(disbursementDetails.details.createdAt)} +
+
+ +
+ +
+ + {disbursementDetails.details.id} + +
+
+
+
+ +
+
+
+ +
+ {renderNumberOrDash( + disbursementDetails.details.stats?.paymentsTotalCount, + )} +
+
+ +
+ +
+ {renderNumberOrDash( + disbursementDetails.details.stats?.paymentsSuccessfulCount, + )} +
+
+ +
+ +
+ {renderNumberOrDash( + disbursementDetails.details.stats?.paymentsFailedCount, + )} +
+
+ +
+ +
+ {renderNumberOrDash( + disbursementDetails.details.stats?.paymentsRemainingCount, + )} +
+
+
+ +
+
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+
+
+
+
+ ); + }; + + const renderReceivers = () => { + if ( + !disbursementDetails.details.receivers || + disbursementDetails.details.receivers.items.length === 0 + ) { + return
There are no receivers
; + } + + return ( +
+ + + + {/* TODO: put back once ready */} + {/* + + */} + Phone number + Wallet provider + Amount + Completed at + Blockchain ID + Org ID + + Payment status + + + + + {disbursementDetails.details.receivers.items.map((r) => ( + + {/* TODO: put back once ready */} + {/* + + */} + + goToReceiver(event, r.id)}> + {r.phoneNumber} + + + {r.provider} + + + + + {r.completedAt ? ( + + {formatDateTime(r.completedAt)} + + ) : null} + + + {r.blockchainId ? ( + + {r.blockchainId} + + ) : null} + + + {r.orgId} + + + + + + ))} + +
+
+
+ ); + }; + + const renderContent = () => { + if (disbursementDetails.errorString) { + return ( + + {disbursementDetails.errorString} + + ); + } + + if ( + !disbursementDetails.details.id && + disbursementDetails.status === "PENDING" + ) { + return
Loading…
; + } + + if (!disbursementId || !disbursementDetails.details.id) { + return null; + } + + return ( + <> + {isPaused ? ( +
+ + Payments are on hold until the disbursement is started again. + +
+ ) : null} + + + + + + + {disbursementDetails.details.name} + + + + + + {isPaused ? ( + + ) : ( + + )} + + + + + + + {renderStatCards()} + + + + + + {disbursementDetails.details.receivers?.pagination?.total && + disbursementDetails.details.receivers?.pagination.total > 0 + ? `${number.format( + disbursementDetails.details.receivers.pagination.total, + )} ` + : ""} + Receivers + + + + +
+ +
+ + { + event.preventDefault(); + setCurrentPage(Number(event.target.value)); + }} + onBlur={handlePageChange} + onNext={handleNextPage} + onPrevious={handlePrevPage} + isLoading={disbursementDetails.status === "PENDING"} + /> +
+
+
+ + {renderReceivers()} + + ); + }; + + return ( + <> + + + {renderContent()} + + + {isPaused ? ( + <> + Restart disbursement + +
+ Click Confirm to restart the disbursement. All remaining + payments will be made automatically to registered receivers. +
+
+ + + + + + ) : ( + <> + Pause disbursement + +
+ Click Confirm to pause all payments still remaining in this + disbursement. The disbursement can be restarted afterwards. +
+
+ + + + + + )} +
+ + ); +}; diff --git a/src/pages/DisbursementDraftDetails.tsx b/src/pages/DisbursementDraftDetails.tsx new file mode 100644 index 0000000..201b39e --- /dev/null +++ b/src/pages/DisbursementDraftDetails.tsx @@ -0,0 +1,311 @@ +import { useCallback, useEffect, useState } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { Badge, Heading, Link, Notification } from "@stellar/design-system"; +import { useDispatch } from "react-redux"; +import { useRedux } from "hooks/useRedux"; +import { useDownloadCsvFile } from "hooks/useDownloadCsvFile"; + +import { AppDispatch } from "store"; +import { + getDisbursementDetailsAction, + setDisbursementDetailsAction, +} from "store/ducks/disbursementDetails"; +import { + clearDisbursementDraftsErrorAction, + resetDisbursementDraftsAction, + setDraftIdAction, + submitDisbursementDraftAction, +} from "store/ducks/disbursementDrafts"; + +import { Breadcrumbs } from "components/Breadcrumbs"; +import { Routes } from "constants/settings"; +import { SectionHeader } from "components/SectionHeader"; +import { Toast } from "components/Toast"; +import { DisbursementDetails } from "components/DisbursementDetails"; +import { DisbursementInstructions } from "components/DisbursementInstructions"; +import { DisbursementButtons } from "components/DisbursementButtons"; +import { DisbursementDraft, DisbursementStep } from "types"; + +export const DisbursementDraftDetails = () => { + const { id: draftId } = useParams(); + + const { disbursements, disbursementDrafts, disbursementDetails } = useRedux( + "disbursements", + "disbursementDrafts", + "disbursementDetails", + ); + + const [draftDetails, setDraftDetails] = useState(); + const [csvFile, setCsvFile] = useState(); + + const [currentStep, setCurrentStep] = useState("preview"); + const [isDraftInProgress, setIsDraftInProgress] = useState(false); + const [isResponseSuccess, setIsResponseSuccess] = useState(false); + + const dispatch: AppDispatch = useDispatch(); + const navigate = useNavigate(); + const { isLoading: csvDownloadIsLoading } = useDownloadCsvFile( + setCsvFile, + true, + ); + + const apiError = disbursementDrafts.errorString; + const isLoading = disbursementDetails.status === "PENDING"; + + const fetchedDisbursementDraft = disbursementDrafts.items.find( + (p) => p.details.id === draftId, + ); + const fetchedDisbursement = disbursements.items.find((p) => p.id === draftId); + + const saveDisbursementDetails = useCallback(() => { + if (fetchedDisbursementDraft) { + dispatch(setDisbursementDetailsAction(fetchedDisbursementDraft)); + } else if (fetchedDisbursement) { + dispatch( + setDisbursementDetailsAction({ + details: fetchedDisbursement, + instructions: { csvFile: undefined, csvName: undefined }, + }), + ); + } + }, [dispatch, fetchedDisbursement, fetchedDisbursementDraft]); + + useEffect(() => { + if ( + disbursementDetails.details.id || + disbursementDetails.status === "PENDING" + ) { + return; + } + + if (fetchedDisbursement?.id) { + saveDisbursementDetails(); + } else if (draftId) { + dispatch(getDisbursementDetailsAction(draftId)); + } + }, [ + draftId, + fetchedDisbursement?.id, + saveDisbursementDetails, + dispatch, + disbursementDetails.details.id, + disbursementDetails.status, + ]); + + useEffect(() => { + setDraftDetails(disbursementDetails); + dispatch(setDraftIdAction(disbursementDetails.details.id)); + }, [disbursementDetails, dispatch]); + + useEffect(() => { + if ( + disbursementDrafts.newDraftId && + disbursementDrafts.status === "SUCCESS" + ) { + // Show success response page + if (disbursementDrafts.actionType === "submit") { + setCurrentStep("confirmation"); + setIsResponseSuccess(true); + } + } + }, [ + disbursementDrafts.actionType, + disbursementDrafts.newDraftId, + disbursementDrafts.status, + ]); + + const resetState = () => { + setCurrentStep("edit"); + setDraftDetails(undefined); + setCsvFile(undefined); + setIsResponseSuccess(false); + dispatch(resetDisbursementDraftsAction()); + }; + + const handleSaveDraft = () => { + alert("TODO: save draft"); + setIsDraftInProgress(true); + }; + + const handleGoBackToDrafts = () => { + navigate(-1); + resetState(); + }; + + const handleSubmitDisbursement = ( + event: React.FormEvent, + ) => { + event.preventDefault(); + if (draftDetails && csvFile) { + dispatch( + submitDisbursementDraftAction({ + details: draftDetails.details, + file: csvFile, + }), + ); + } + }; + + const handleViewDetails = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + navigate(`${Routes.DISBURSEMENTS}/${disbursementDetails.details.id}`); + resetState(); + }; + + const renderButtons = (variant: DisbursementStep) => { + return ( + { + dispatch(resetDisbursementDraftsAction()); + }} + // TODO: enable when update draft endpoint is ready + isDraftDisabled={true} + isSubmitDisabled={!(Boolean(draftDetails) && Boolean(csvFile))} + isDraftPending={disbursementDrafts.status === "PENDING"} + actionType={disbursementDrafts.actionType} + /> + ); + }; + + const renderContent = () => { + if (isLoading || csvDownloadIsLoading) { + return
Loading…
; + } + + if (!["READY", "DRAFT"].includes(disbursementDetails.details.status)) { + return ( +
{`Disbursement ID ${disbursementDetails.details.id} is not a draft. Current status is ${disbursementDetails.details.status}.`}
+ ); + } + + // Confirmation + if (currentStep === "confirmation") { + return ( + <> + {isResponseSuccess ? ( + +
+ Payments will begin automatically to receivers who have + registered their wallet. Click View to track your disbursement + in real-time. +
+ +
+ + View + + { + setIsResponseSuccess(false); + }} + > + Dismiss + +
+
+ ) : null} + +
+ + + {renderButtons("confirmation")} + + + ); + } + + return ( +
+ + { + if (apiError) { + dispatch(clearDisbursementDraftsErrorAction()); + } + setCsvFile(file); + }} + /> + + {renderButtons("preview")} + + ); + }; + + return ( + <> + + + + + + + Disbursement draft + + + + + + Changes saved + + + + + + {apiError ? ( + +
{apiError}
+ {disbursementDrafts.errorExtras ? ( +
    + {Object.entries(disbursementDrafts.errorExtras).map( + ([key, value]) => ( +
  • {`${key}: ${value}`}
  • + ), + )} +
+ ) : null} +
+ ) : null} + + {renderContent()} + + ); +}; diff --git a/src/pages/Disbursements.tsx b/src/pages/Disbursements.tsx new file mode 100644 index 0000000..7b85b04 --- /dev/null +++ b/src/pages/Disbursements.tsx @@ -0,0 +1,330 @@ +import { useEffect, useState } from "react"; +import { Button, Heading, Icon, Input, Select } from "@stellar/design-system"; +import { useDispatch } from "react-redux"; +import { useNavigate } from "react-router-dom"; + +import { FilterMenu } from "components/FilterMenu"; +import { DisbursementsTable } from "components/DisbursementsTable"; +import { NewDisbursementButton } from "components/NewDisbursementButton"; +import { Pagination } from "components/Pagination"; +import { SearchInput } from "components/SearchInput"; +import { SectionHeader } from "components/SectionHeader"; +import { ShowForRoles } from "components/ShowForRoles"; + +import { + PAGE_LIMIT_OPTIONS, + Routes, + UI_STATUS_DISBURSEMENT, +} from "constants/settings"; +import { number } from "helpers/formatIntlNumber"; +import { useRedux } from "hooks/useRedux"; +import { AppDispatch } from "store"; +import { + getDisbursementsAction, + getDisbursementsWithParamsAction, +} from "store/ducks/disbursements"; +import { resetDisbursementDetailsAction } from "store/ducks/disbursementDetails"; +import { setDraftIdAction } from "store/ducks/disbursementDrafts"; +import { CommonFilters, SortByDisbursements, SortDirection } from "types"; + +export const Disbursements = () => { + const { disbursements } = useRedux("disbursements"); + + const [currentPage, setCurrentPage] = useState(1); + const [pageLimit, setPageLimit] = useState(20); + + const INIT_STATUS = UI_STATUS_DISBURSEMENT; + + const initFilters: CommonFilters = { + // We don't want to show DRAFTS here + status: INIT_STATUS, + created_at_after: "", + created_at_before: "", + }; + + const [filters, setFilters] = useState(initFilters); + + const isFiltersSelected = + Object.values(filters) + // Filter out init status, so that UI doesn't treat it as selected value + .filter((v) => v !== INIT_STATUS) + .filter((v) => Boolean(v)).length > 0; + + const dispatch: AppDispatch = useDispatch(); + const navigate = useNavigate(); + + useEffect(() => { + dispatch(getDisbursementsAction()); + dispatch(resetDisbursementDetailsAction()); + dispatch(setDraftIdAction(undefined)); + }, [dispatch]); + + const apiError = + disbursements.status === "ERROR" && disbursements.errorString; + const maxPages = disbursements.pagination?.pages || 1; + const isSearchInProgress = Boolean( + disbursements.searchParams?.q && disbursements.status === "PENDING", + ); + + const goToDrafts = () => { + navigate(Routes.DISBURSEMENT_DRAFTS); + }; + + const handleSearchChange = (searchText?: string) => { + dispatch( + getDisbursementsWithParamsAction({ + page: "1", + ...filters, + q: searchText, + }), + ); + + setCurrentPage(1); + }; + + const handleFilterChange = ( + event: React.ChangeEvent, + ) => { + setFilters({ + ...filters, + [event.target.id]: event.target.value, + }); + }; + + const handleFilterSubmit = () => { + dispatch( + getDisbursementsWithParamsAction({ + page: "1", + ...filters, + }), + ); + + setCurrentPage(1); + }; + + const handleFilterReset = () => { + dispatch( + getDisbursementsWithParamsAction({ + page: "1", + ...initFilters, + }), + ); + + setFilters(initFilters); + setCurrentPage(1); + }; + + const handleSort = ( + sort?: SortByDisbursements, + direction?: SortDirection, + ) => { + if (!sort || !direction || direction === "default") { + dispatch( + getDisbursementsWithParamsAction({ + page: "1", + sort: undefined, + direction: undefined, + }), + ); + } else { + dispatch( + getDisbursementsWithParamsAction({ + page: "1", + sort, + direction, + }), + ); + } + + setCurrentPage(1); + }; + + const handleExport = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + alert("TODO: handle export"); + }; + + const handlePageLimitChange = ( + event: React.ChangeEvent, + ) => { + event.preventDefault(); + + const pageLimit = Number(event.target.value); + setPageLimit(pageLimit); + setCurrentPage(1); + + // Need to make sure we'll be loading page 1 + dispatch( + getDisbursementsWithParamsAction({ + page_limit: pageLimit.toString(), + page: "1", + }), + ); + }; + + const handlePageChange = (currentPage: number) => { + dispatch( + getDisbursementsWithParamsAction({ page: currentPage.toString() }), + ); + }; + + const handleNextPage = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + const newPage = currentPage + 1; + + setCurrentPage(newPage); + handlePageChange(newPage); + }; + + const handlePrevPage = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + const newPage = currentPage - 1; + + setCurrentPage(newPage); + handlePageChange(newPage); + }; + + return ( + <> + + + + + {disbursements.pagination?.total && + disbursements.pagination.total > 0 + ? `${number.format(disbursements.pagination.total)} ` + : ""} + Disbursements + + + + + + + + + + + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+ + +
+ + +
+ +
+ + { + event.preventDefault(); + setCurrentPage(Number(event.target.value)); + }} + onBlur={handlePageChange} + onNext={handleNextPage} + onPrevious={handlePrevPage} + isLoading={disbursements.status === "PENDING"} + /> +
+
+
+ + + + ); +}; diff --git a/src/pages/DisbursementsDrafts.tsx b/src/pages/DisbursementsDrafts.tsx new file mode 100644 index 0000000..ff5462e --- /dev/null +++ b/src/pages/DisbursementsDrafts.tsx @@ -0,0 +1,173 @@ +import { useEffect } from "react"; +import { useDispatch } from "react-redux"; +import { useNavigate } from "react-router-dom"; +import { + Card, + Heading, + Icon, + Link, + Notification, +} from "@stellar/design-system"; + +import { Routes } from "constants/settings"; +import { formatDateTime } from "helpers/formatIntlDateTime"; +import { useRedux } from "hooks/useRedux"; +import { AppDispatch } from "store"; +import { + getDisbursementDraftsAction, + setDraftIdAction, +} from "store/ducks/disbursementDrafts"; +import { resetDisbursementDetailsAction } from "store/ducks/disbursementDetails"; + +import { Breadcrumbs } from "components/Breadcrumbs"; +import { NewDisbursementButton } from "components/NewDisbursementButton"; +import { SectionHeader } from "components/SectionHeader"; +import { Table } from "components/Table"; +import { DisbursementDraft } from "types"; + +export const DisbursementsDrafts = () => { + const { disbursementDrafts } = useRedux("disbursementDrafts"); + + const dispatch: AppDispatch = useDispatch(); + const navigate = useNavigate(); + + useEffect(() => { + if (!disbursementDrafts.status || disbursementDrafts.actionType) { + dispatch(getDisbursementDraftsAction()); + dispatch(resetDisbursementDetailsAction()); + dispatch(setDraftIdAction(undefined)); + } + }, [disbursementDrafts.actionType, disbursementDrafts.status, dispatch]); + + const apiError = + disbursementDrafts.status === "ERROR" && disbursementDrafts.errorString; + const isLoading = + disbursementDrafts.items.length === 0 && + disbursementDrafts.status === "PENDING"; + const doneLoading = + disbursementDrafts.status && disbursementDrafts.status !== "PENDING"; + const hasData = doneLoading && disbursementDrafts.items.length > 0; + + const handleEditDraft = ( + event: React.MouseEvent, + item: DisbursementDraft, + ) => { + event.preventDefault(); + navigate(`${Routes.DISBURSEMENT_DRAFTS}/${item.details.id}`); + }; + + const renderContent = () => { + if (isLoading) { + return
Loading…
; + } + + return ( + <> + {/* TODO: add sorting by name and created at */} + {hasData ? ( +
+ + + + Disbursement name + Country + Asset + Created at + + + + + {disbursementDrafts.items.map((item: DisbursementDraft) => { + const formattedDate = formatDateTime( + item.details.createdAt, + ); + + return ( + + + handleEditDraft(event, item)} + title={item.details.name} + > + {item.details.name} + + + + {item.details.country.name} + + + {item.details.asset.code} + + + + {formattedDate} + + + + {item.details.fileName ? ( + + + + ) : null} + + + ); + })} + +
+
+
+ ) : apiError ? null : ( +
There are no saved drafts
+ )} + + ); + }; + + return ( + <> + + + + + + + Disbursement drafts + + + + + + + + + + {apiError ? ( + +
{apiError}
+
+ ) : null} + + {renderContent()} + + ); +}; diff --git a/src/pages/DisbursementsNew.tsx b/src/pages/DisbursementsNew.tsx new file mode 100644 index 0000000..e203cdc --- /dev/null +++ b/src/pages/DisbursementsNew.tsx @@ -0,0 +1,351 @@ +import { useEffect, useState } from "react"; +import { + Badge, + Card, + Heading, + Notification, + Title, +} from "@stellar/design-system"; +import { useDispatch } from "react-redux"; +import { useNavigate } from "react-router-dom"; + +import { AppDispatch } from "store"; +import { + clearDisbursementDraftsErrorAction, + resetDisbursementDraftsAction, + saveDisbursementDraftAction, + submitDisbursementDraftAction, +} from "store/ducks/disbursementDrafts"; +import { useRedux } from "hooks/useRedux"; +import { useOrgAccountInfo } from "hooks/useOrgAccountInfo"; +import { Routes } from "constants/settings"; + +import { Breadcrumbs } from "components/Breadcrumbs"; +import { SectionHeader } from "components/SectionHeader"; +import { Toast } from "components/Toast"; +import { DisbursementDetails } from "components/DisbursementDetails"; +import { DisbursementInstructions } from "components/DisbursementInstructions"; +import { DisbursementButtons } from "components/DisbursementButtons"; +import { NotificationWithButtons } from "components/NotificationWithButtons"; +import { InfoTooltip } from "components/InfoTooltip"; +import { AccountBalances } from "components/AccountBalances"; + +import { Disbursement, DisbursementStep } from "types"; + +export const DisbursementsNew = () => { + const { disbursementDrafts, organization } = useRedux( + "disbursementDrafts", + "organization", + ); + const { assetBalances, distributionAccountPublicKey } = organization.data; + + const [draftDetails, setDraftDetails] = useState(); + const [isDetailsValid, setIsDetailsValid] = useState(false); + const [csvFile, setCsvFile] = useState(); + + const [currentStep, setCurrentStep] = useState("edit"); + const [isDraftInProgress, setIsDraftInProgress] = useState(false); + const [isSavedDraftMessageVisible, setIsSavedDraftMessageVisible] = + useState(false); + const [isResponseSuccess, setIsResponseSuccess] = useState(false); + + const isDraftEnabled = isDetailsValid; + const isReviewEnabled = isDraftEnabled && Boolean(csvFile); + + const dispatch: AppDispatch = useDispatch(); + const navigate = useNavigate(); + + const apiError = + disbursementDrafts.status === "ERROR" && disbursementDrafts.errorString; + + useEffect(() => { + if ( + disbursementDrafts.newDraftId && + disbursementDrafts.status === "SUCCESS" + ) { + // Show success response page + if (disbursementDrafts.actionType === "submit") { + setCurrentStep("confirmation"); + setIsResponseSuccess(true); + + setIsSavedDraftMessageVisible(false); + } + + // Show message and toast when draft is saved + if (disbursementDrafts.actionType === "save") { + setIsSavedDraftMessageVisible(true); + setIsDraftInProgress(true); + } + } + }, [ + disbursementDrafts.actionType, + disbursementDrafts.newDraftId, + disbursementDrafts.status, + ]); + + useOrgAccountInfo(distributionAccountPublicKey); + + const resetState = () => { + setCurrentStep("edit"); + setDraftDetails(undefined); + setIsDetailsValid(false); + setCsvFile(undefined); + setIsResponseSuccess(false); + dispatch(resetDisbursementDraftsAction()); + }; + + const handleDiscard = () => { + dispatch(resetDisbursementDraftsAction()); + navigate(Routes.DISBURSEMENTS); + }; + + // TODO: figure out how to disable save if nothing has changed + const handleSaveDraft = async () => { + setIsSavedDraftMessageVisible(false); + + if (draftDetails) { + dispatch( + saveDisbursementDraftAction({ details: draftDetails, file: csvFile }), + ); + } + }; + + const handleReview = (event: React.FormEvent) => { + event.preventDefault(); + setCurrentStep("preview"); + setIsSavedDraftMessageVisible(false); + }; + + const handleGoBackToEdit = () => { + dispatch(clearDisbursementDraftsErrorAction()); + setCurrentStep("edit"); + }; + + const handleSubmitDisbursement = ( + event: React.FormEvent, + ) => { + event.preventDefault(); + if (draftDetails && csvFile) { + dispatch( + submitDisbursementDraftAction({ details: draftDetails, file: csvFile }), + ); + } + }; + + const handleStartNewDisbursement = () => { + resetState(); + }; + + const handleCsvFileChange = (file?: File) => { + if (apiError) { + dispatch(clearDisbursementDraftsErrorAction()); + } + setCsvFile(file); + }; + + const handleViewDetails = () => { + navigate(`${Routes.DISBURSEMENTS}/${disbursementDrafts.newDraftId}`); + resetState(); + }; + + const renderButtons = (variant: DisbursementStep) => { + return ( + { + dispatch(resetDisbursementDraftsAction()); + }} + // TODO: update save draft action when endpoint is ready + isDraftDisabled={ + !isDraftEnabled || + Boolean(disbursementDrafts.newDraftId && currentStep === "preview") + } + isSubmitDisabled={!(draftDetails && csvFile)} + isReviewDisabled={!isReviewEnabled} + isDraftPending={disbursementDrafts.status === "PENDING"} + actionType={disbursementDrafts.actionType} + /> + ); + }; + + const renderCurrentStep = () => { + // Preview + if (currentStep === "preview") { + return ( +
+ + + + {renderButtons("preview")} + + ); + } + + // Confirmation + if (currentStep === "confirmation") { + return ( + <> + {isResponseSuccess ? ( + { + setIsResponseSuccess(false); + }, + }, + ]} + > + Payments will begin automatically to receivers who have registered + their wallet. + + ) : null} + +
+ + + {renderButtons("confirmation")} + + + ); + } + + // Edit + return ( + <> +
+ + + Current balance + +
+ +
+
+ + { + if (apiError) { + dispatch(clearDisbursementDraftsErrorAction()); + } + + setDraftDetails(updatedState); + }} + onValidate={(isValid) => { + setIsDetailsValid(isValid); + }} + /> + + + + {renderButtons("edit")} + + + ); + }; + + return ( + <> + + + + + + + New disbursement + + + + + + Changes saved + + + + + + {isSavedDraftMessageVisible ? ( + { + navigate(Routes.DISBURSEMENT_DRAFTS); + }, + }, + { + label: "Dismiss", + onClick: () => setIsSavedDraftMessageVisible(false), + }, + ]} + > + Your disbursement has been saved. + + ) : null} + + {apiError ? ( + +
{apiError}
+ {disbursementDrafts.errorExtras ? ( +
    + {Object.entries(disbursementDrafts.errorExtras).map( + ([key, value]) => ( +
  • {`${key}: ${value}`}
  • + ), + )} +
+ ) : null} +
+ ) : null} + + {renderCurrentStep()} + + ); +}; diff --git a/src/pages/ForgotPassword.tsx b/src/pages/ForgotPassword.tsx new file mode 100644 index 0000000..a9540d6 --- /dev/null +++ b/src/pages/ForgotPassword.tsx @@ -0,0 +1,107 @@ +import { useEffect, useRef, useState } from "react"; +import Recaptcha from "react-google-recaptcha"; +import { + Heading, + Input, + Button, + Notification, + Link, +} from "@stellar/design-system"; +import { useDispatch } from "react-redux"; +import { useNavigate } from "react-router-dom"; + +import { AppDispatch } from "store"; +import { sendResetPasswordLinkAction } from "store/ducks/forgotPassword"; +import { RECAPTCHA_SITE_KEY } from "constants/settings"; +import { useRedux } from "hooks/useRedux"; + +export const ForgotPassword = () => { + const dispatch: AppDispatch = useDispatch(); + const navigate = useNavigate(); + const recaptchaRef = useRef(null); + + const { forgotPassword } = useRedux("forgotPassword"); + const [email, setEmail] = useState(""); + const [recaptchaToken, setRecaptchaToken] = useState(""); + + const handleForgotPassword = (event: React.FormEvent) => { + event.preventDefault(); + dispatch(sendResetPasswordLinkAction({ email, recaptchaToken })); + recaptchaRef.current?.reset(); + setRecaptchaToken(""); + }; + + const onRecaptchaSubmit = (token: string | null) => { + if (token) { + setRecaptchaToken(token); + } + }; + + useEffect(() => { + if (forgotPassword.status === "SUCCESS") { + setEmail(""); + } + }, [forgotPassword.status]); + + const goToSignIn = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + navigate("/"); + }; + + return ( + <> +
+ {forgotPassword.status === "SUCCESS" && ( + + {forgotPassword.response} + + )} + + {forgotPassword.errorString && ( + + {forgotPassword.errorString} + + )} + +
+ + Forgot password + + + setEmail(e.target.value)} + value={email} + type="email" + /> + + + + + + Sign in + + +
+ + ); +}; diff --git a/src/pages/Help.tsx b/src/pages/Help.tsx new file mode 100644 index 0000000..9d00b48 --- /dev/null +++ b/src/pages/Help.tsx @@ -0,0 +1,71 @@ +import { Heading } from "@stellar/design-system"; +import { ExpandContent } from "components/ExpandContent"; +import { SectionHeader } from "components/SectionHeader"; + +const FAQ = [ + { + question: + "What information do I need to upload to create a new disbursement?", + answer: + "First select the country, asset, and wallet provider for your disbursement. Then upload a list of receivers in csv format with the following fields: phone, id, amount, verification. Phone number should be in international format with the plus sign. ID is a unique identifier per receiver. This should be a consistent identifier you use to track individuals in your internal systems. Amount is denominated in the asset you chose in the dropdown and should only contain the number, not the asset name. Verification is a piece of additional information the receiver will verify when signing up for a wallet in order to receive their funds. This could be date of birth, national ID number, or a personal PIN. It should be something the receiver knows and has provided to your organization.", + }, + { + question: "How can I track my payments?", + answer: + "You can view payments within a disbursement by going to the Disbursements page and then clicking into a specific disbursement. You can also see individual payments on the Payments screen. Clicking into an individual payment provides detailed information such as status over time and wallet address of the receiver. Payments can be in ready, pending, paused, success, or failure status.", + }, + { + question: "How do I pause a disbursement after it has been created?", + answer: + "You can pause a disbursement to prevent further payments from being sent. Click into a specific disbursement and click the ‘Pause’ button. This will not impact payments that have already been sent. The disbursement will remain paused until it is started again.", + }, + { + question: "How do I fund my distribution account?", + answer: + "You can find your distribution account public key by going to the Wallets page. Before you can send disbursements, you will need to fund the distribution account as it is the source of funds for payments. First acquire the digital assets you want to send. This could mean buying them on an exchange, minting them through an entity like Circle, or accepting crypto donations. Once you have the Stellar-based assets and are ready to disburse them, send them to the SDP distribution account. You can easily copy and paste the distribution account public key found on the Wallets page. Once the funds are in the distribution account, they are available for disbursements.", + }, + { + question: "How do I know my receivers accessed their money?", + answer: + "Payments are only sent once a receiver has registered for a digital wallet after being invited to receive money through the SDP. This means they have to actively participate in the process by claiming their money and verifying their identity. After a receiver has linked their wallet, subsequent payments will automatically be sent when a new disbursement is submitted. You can check to see if a receiver is using their money by clicking into a receiver and viewing their public blockchain key on a blockchain explorer like stellar.expert (available as a link in your dashboard as well). The blockchain explorer shows every transaction that has been done in the receiver’s wallet on an anonymized basis, as well as current balance.", + }, + { + question: "How do I track payments on the Stellar blockchain?", + answer: + "You can view all Stellar transactions on blockchain explorers like stellar.expert. The easiest way to view payments is by searching for either your distribution account public key or the public key of a specific receiver. This will allow you to see all activity on the account. There are links to stellar.expert directly in your SDP dashboard as well.", + }, + { + question: "What should I do if the receiver’s information is incorrect?", + answer: + "You can edit certain information on receivers in case of mistakes. Please make sure to confirm with the receiver before editing information.", + }, + { + question: "Can I take back funds after they have been sent?", + answer: + "No. Once funds are sent from your organization to the receiver, it is final. A receiver’s digital wallet is like a bank account in that they have full agency over the funds.", + }, +]; + +export const Help = () => { + return ( + <> + + + + + Help + + + + + +
+ {FAQ.map((item, index) => ( + + {item.answer} + + ))} +
+ + ); +}; diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx new file mode 100644 index 0000000..60099bc --- /dev/null +++ b/src/pages/Home.tsx @@ -0,0 +1,126 @@ +import { useEffect } from "react"; +import { useDispatch } from "react-redux"; +import { useNavigate } from "react-router-dom"; +import { Button, Heading, Icon } from "@stellar/design-system"; + +import { AppDispatch } from "store"; +import { getDisbursementsAction } from "store/ducks/disbursements"; +import { resetDisbursementDetailsAction } from "store/ducks/disbursementDetails"; +import { setDraftIdAction } from "store/ducks/disbursementDrafts"; +import { useRedux } from "hooks/useRedux"; +import { Routes } from "constants/settings"; + +import { SectionHeader } from "components/SectionHeader"; +import { ShowForRoles } from "components/ShowForRoles"; +import { DisbursementsTable } from "components/DisbursementsTable"; +import { DashboardAnalytics } from "components/DashboardAnalytics"; +import { useIsUserRoleAccepted } from "hooks/useIsUserRoleAccepted"; + +export const Home = () => { + const { disbursements, userAccount } = useRedux( + "disbursements", + "userAccount", + ); + const { isRoleAccepted } = useIsUserRoleAccepted([ + "business", + "financial_controller", + "owner", + ]); + + const dispatch: AppDispatch = useDispatch(); + const navigate = useNavigate(); + + useEffect(() => { + if (userAccount.isAuthenticated) { + if (isRoleAccepted) { + dispatch(getDisbursementsAction()); + } + dispatch(resetDisbursementDetailsAction()); + dispatch(setDraftIdAction(undefined)); + } + }, [dispatch, isRoleAccepted, userAccount.isAuthenticated]); + + const apiErrorDisbursements = + disbursements.status === "ERROR" && disbursements.errorString; + + const goToAnalytics = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + navigate(Routes.ANALYTICS); + }; + + const goToDisbursements = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + navigate(Routes.DISBURSEMENTS); + }; + + const goToNewDisbursement = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + navigate(Routes.DISBURSEMENT_NEW); + }; + + return ( + <> + + + + + Dashboard + + + + + + + + +
+ +
+ + + + + + + Recent disbursements + + + + + + + + + + + + + + + ); +}; diff --git a/src/pages/MFAuth.tsx b/src/pages/MFAuth.tsx new file mode 100644 index 0000000..a6498a4 --- /dev/null +++ b/src/pages/MFAuth.tsx @@ -0,0 +1,168 @@ +import { useEffect, useRef, useState } from "react"; +import Recaptcha from "react-google-recaptcha"; +import { + Heading, + Input, + Button, + Notification, + Link, + Checkbox, +} from "@stellar/design-system"; +import { useDispatch } from "react-redux"; +import { useNavigate, useLocation } from "react-router-dom"; +import { v4 as uuidv4 } from "uuid"; + +import { AppDispatch, resetStoreAction } from "store"; +import { + Routes, + USE_SSO, + RECAPTCHA_SITE_KEY, + LOCAL_STORAGE_DEVICE_ID, +} from "constants/settings"; +import { useRedux } from "hooks/useRedux"; +import { mfaAction, signInAction } from "store/ducks/userAccount"; + +export const MFAuth = () => { + const dispatch: AppDispatch = useDispatch(); + const navigate = useNavigate(); + const location = useLocation(); + const recaptchaRef = useRef(null); + + const { userAccount } = useRedux("userAccount"); + const [recaptchaToken, setRecaptchaToken] = useState(""); + const [mfaCode, setMfaCode] = useState(""); + const [rememberMe, setRememberMe] = useState(false); + const [deviceId, setDeviceId] = useState(""); + + const { email, password } = location.state; + + useEffect(() => { + const storedDeviceId = localStorage.getItem(LOCAL_STORAGE_DEVICE_ID); + if (!storedDeviceId) { + const newDeviceId = uuidv4(); + localStorage.setItem(LOCAL_STORAGE_DEVICE_ID, newDeviceId); + setDeviceId(newDeviceId); + } else { + setDeviceId(storedDeviceId); + } + }, [deviceId]); + + useEffect(() => { + if (userAccount.isAuthenticated) { + navigate({ + pathname: userAccount.restoredPathname ?? Routes.HOME, + search: location.search, + }); + } + }, [ + location.search, + navigate, + userAccount.isAuthenticated, + userAccount.restoredPathname, + ]); + + const onRecaptchaSubmit = (token: string | null) => { + if (token) { + setRecaptchaToken(token); + } + }; + + const handleSubmit = async (event: React.FormEvent) => { + event.preventDefault(); + dispatch(resetStoreAction()); + + const headers = { + "Device-ID": deviceId, + }; + + dispatch(mfaAction({ mfaCode, rememberMe, recaptchaToken, headers })); + + recaptchaRef.current?.reset(); + }; + + const resendVerificationCode = async ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + dispatch(resetStoreAction()); + + const headers = { + "Device-ID": deviceId, + }; + + if (email && password) { + dispatch(signInAction({ email, password, recaptchaToken, headers })); + } + recaptchaRef.current?.reset(); + }; + + return ( + <> +
+ {userAccount.errorString && ( + + {userAccount.errorString} + + )} +
+ + Verify your identity + + +
+ Enter the 6 digit code that was sent to your email. Didn’t get + anything?{" "} + + Resend code + +
+ + {!USE_SSO && ( + <> + setMfaCode(e.target.value)} + type="text" + /> + + setRememberMe(e.target.checked)} + /> + + + + + + )} + +
+ + ); +}; diff --git a/src/pages/NotFound.tsx b/src/pages/NotFound.tsx new file mode 100644 index 0000000..04326cd --- /dev/null +++ b/src/pages/NotFound.tsx @@ -0,0 +1,23 @@ +import { useNavigate } from "react-router-dom"; +import { Button, Heading, Paragraph } from "@stellar/design-system"; +import { Routes } from "constants/settings"; + +export const NotFound = () => { + const navigate = useNavigate(); + + const handleBack = () => { + navigate(Routes.HOME); + }; + + return ( +
+ + Error 404 + + Sorry, that page couldn’t be found. + +
+ ); +}; diff --git a/src/pages/PaymentDetails.tsx b/src/pages/PaymentDetails.tsx new file mode 100644 index 0000000..daa151d --- /dev/null +++ b/src/pages/PaymentDetails.tsx @@ -0,0 +1,357 @@ +import { useCallback, useEffect } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { + Card, + Heading, + Link, + Notification, + Profile, +} from "@stellar/design-system"; +import { useDispatch } from "react-redux"; + +import { AppDispatch } from "store"; +import { + getPaymentDetailsAction, + getPaymentDetailsReceiverAction, + setPaymentDetailsAction, +} from "store/ducks/paymentDetails"; +import { Routes, STELLAR_EXPERT_URL } from "constants/settings"; +import { formatDateTime } from "helpers/formatIntlDateTime"; +import { shortenString } from "helpers/shortenString"; +import { useRedux } from "hooks/useRedux"; + +import { Breadcrumbs } from "components/Breadcrumbs"; +import { SectionHeader } from "components/SectionHeader"; +import { Table } from "components/Table"; +import { PaymentStatus } from "components/PaymentStatus"; +import { ReceiverStatus } from "components/ReceiverStatus"; +import { AssetAmount } from "components/AssetAmount"; +import { MultipleAmounts } from "components/MultipleAmounts"; +import { RetryFailedPayment } from "components/RetryFailedPayment"; + +export const PaymentDetails = () => { + const { id: paymentId } = useParams(); + const { payments, paymentDetails } = useRedux("payments", "paymentDetails"); + + const dispatch: AppDispatch = useDispatch(); + const navigate = useNavigate(); + + const fetchedPayment = payments.items.find((p) => p.id === paymentId); + const { receiver } = paymentDetails; + + const savePaymentDetails = useCallback(() => { + if (fetchedPayment) { + dispatch(setPaymentDetailsAction(fetchedPayment)); + } + }, [dispatch, fetchedPayment]); + + // TODO: once we have data for the whole flow, figure out when to clear payment details + + useEffect(() => { + if (fetchedPayment?.id) { + savePaymentDetails(); + } else { + if (paymentId) { + dispatch(getPaymentDetailsAction(paymentId)); + } + } + }, [paymentId, fetchedPayment?.id, savePaymentDetails, dispatch]); + + useEffect(() => { + if (paymentDetails.details.receiverId) { + dispatch( + getPaymentDetailsReceiverAction(paymentDetails.details.receiverId), + ); + } + }, [paymentDetails.details.receiverId, dispatch]); + + const goToDisbursement = ( + event: React.MouseEvent, + disbursementId: string, + ) => { + event.preventDefault(); + navigate(`${Routes.DISBURSEMENTS}/${disbursementId}`); + }; + + const goToReceiverDetails = ( + event: React.MouseEvent, + receiverId: string, + ) => { + event?.preventDefault(); + navigate(`${Routes.RECEIVERS}/${receiverId}`); + }; + + const renderContent = () => { + if (paymentDetails.errorString) { + return ( + + {paymentDetails.errorString} + + ); + } + + return ( + <> +
+ { + dispatch(getPaymentDetailsAction(paymentDetails.details.id)); + }} + /> + + + + + + {paymentId} + + + + + +
+ +
+
+ +
{formatDateTime(paymentDetails.details.createdAt)}
+
+ +
+ +
+ + goToDisbursement( + event, + paymentDetails.details.disbursementId, + ) + } + > + {paymentDetails.details.disbursementName} + +
+
+
+
+ + +
+
+ +
+ +
+
+ +
+ +
+ {paymentDetails.details.transactionId ? ( + + {shortenString( + paymentDetails.details.transactionId, + 15, + )} + + ) : ( + "-" + )} +
+
+
+
+ + +
+
+ +
+ {paymentDetails.details.senderAddress ? ( + + ) : ( + "-" + )} +
+
+
+
+
+
+ + {/* Status history */} +
+ + Status history + + + + + + Status + Message + + Updated at + + + + + {paymentDetails.statusHistory.map((h) => ( + + + + + + + {h.message || "-"} + + + + + {formatDateTime(h.updatedAt)} + + + + ))} + +
+
+
+ + {/* Receiver */} +
+ + Receiver + + + + + + {/* TODO: put back once ready */} + {/* + + */} + Phone number + Wallet address + Wallet provider + + Total payments + + + Successful + + Created at + + Amount(s) received + + Status + + + + + {/* TODO: put back once ready */} + {/* + + */} + + {receiver?.phoneNumber ? ( + + goToReceiverDetails(event, receiver.id) + } + > + {receiver.phoneNumber} + + ) : ( + "-" + )} + + + {receiver?.walletAddress ? ( + + ) : ( + "-" + )} + + + {receiver?.provider || "-"} + + + {receiver?.totalPaymentsCount || "-"} + + + {receiver?.successfulPaymentsCount || "-"} + + + + {receiver?.createdAt + ? formatDateTime(receiver.createdAt) + : "-"} + + + + + + + {receiver?.status ? ( + + ) : ( + "-" + )} + + + +
+
+
+ + ); + }; + + return ( + <> + + + {renderContent()} + + ); +}; diff --git a/src/pages/Payments.tsx b/src/pages/Payments.tsx new file mode 100644 index 0000000..7986a35 --- /dev/null +++ b/src/pages/Payments.tsx @@ -0,0 +1,262 @@ +import { useEffect, useState } from "react"; +import { Button, Heading, Icon, Input, Select } from "@stellar/design-system"; +import { useDispatch } from "react-redux"; + +import { FilterMenu } from "components/FilterMenu"; +import { Pagination } from "components/Pagination"; +import { PaymentsTable } from "components/PaymentsTable"; +import { SearchInput } from "components/SearchInput"; +import { SectionHeader } from "components/SectionHeader"; + +import { PAGE_LIMIT_OPTIONS } from "constants/settings"; +import { number } from "helpers/formatIntlNumber"; +import { useRedux } from "hooks/useRedux"; +import { AppDispatch } from "store"; +import { + getPaymentsWithParamsAction, + getPaymentsAction, +} from "store/ducks/payments"; +import { CommonFilters } from "types"; + +export const Payments = () => { + const { payments } = useRedux("payments"); + + // TODO: handle search in progress + const [isSearchInProgress] = useState(false); + const [currentPage, setCurrentPage] = useState(1); + const [pageLimit, setPageLimit] = useState(20); + + const initFilters: CommonFilters = { + status: "", + created_at_after: "", + created_at_before: "", + }; + + const [filters, setFilters] = useState(initFilters); + + const isFiltersSelected = + Object.values(filters).filter((v) => Boolean(v)).length > 0; + + const dispatch: AppDispatch = useDispatch(); + + useEffect(() => { + dispatch(getPaymentsAction()); + }, [dispatch]); + + const apiError = payments.status === "ERROR" && payments.errorString; + const maxPages = payments.pagination?.pages || 1; + + const handleSearchSubmit = () => { + alert("TODO: search submit"); + }; + + const handleSearchClear = () => { + alert("TODO: search clear"); + }; + + const handleFilterChange = ( + event: React.ChangeEvent, + ) => { + setFilters({ + ...filters, + [event.target.id]: event.target.value, + }); + }; + + const handleFilterSubmit = () => { + dispatch( + getPaymentsWithParamsAction({ + page: "1", + ...filters, + }), + ); + + setCurrentPage(1); + }; + + const handleFilterReset = () => { + dispatch( + getPaymentsWithParamsAction({ + page: "1", + ...initFilters, + }), + ); + + setFilters(initFilters); + setCurrentPage(1); + }; + + const handleExport = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + alert("TODO: handle export"); + }; + + const handlePageLimitChange = ( + event: React.ChangeEvent, + ) => { + event.preventDefault(); + + const pageLimit = Number(event.target.value); + setPageLimit(pageLimit); + setCurrentPage(1); + + // Need to make sure we'll be loading page 1 + dispatch( + getPaymentsWithParamsAction({ + page_limit: pageLimit.toString(), + page: "1", + }), + ); + }; + + const handlePageChange = (currentPage: number) => { + dispatch(getPaymentsWithParamsAction({ page: currentPage.toString() })); + }; + + const handleNextPage = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + const newPage = currentPage + 1; + + setCurrentPage(newPage); + handlePageChange(newPage); + }; + + const handlePrevPage = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + const newPage = currentPage - 1; + + setCurrentPage(newPage); + handlePageChange(newPage); + }; + + return ( + <> + + + + + {payments.pagination?.total && payments.pagination.total > 0 + ? `${number.format(payments.pagination.total)} ` + : ""} + Payments + + + + + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+ + +
+ + +
+ +
+ + { + event.preventDefault(); + setCurrentPage(Number(event.target.value)); + }} + onBlur={handlePageChange} + onNext={handleNextPage} + onPrevious={handlePrevPage} + isLoading={payments.status === "PENDING"} + /> +
+
+
+ + + + ); +}; diff --git a/src/pages/Profile.tsx b/src/pages/Profile.tsx new file mode 100644 index 0000000..26c59b0 --- /dev/null +++ b/src/pages/Profile.tsx @@ -0,0 +1,594 @@ +import { useEffect, useState } from "react"; +import { useDispatch } from "react-redux"; +import { useNavigate } from "react-router-dom"; +import { + Button, + Card, + Heading, + Icon, + Input, + Link, + Select, + Notification, +} from "@stellar/design-system"; + +import { DropdownMenu } from "components/DropdownMenu"; +import { FileUpload } from "components/FileUpload"; +import { InfoTooltip } from "components/InfoTooltip"; +import { MoreMenuButton } from "components/MoreMenuButton"; +import { NotificationWithButtons } from "components/NotificationWithButtons"; +import { SectionHeader } from "components/SectionHeader"; + +import { + LOCAL_STORAGE_SESSION_TOKEN, + Routes, + USE_SSO, +} from "constants/settings"; +import { singleUserStore } from "helpers/singleSingOn"; +import { userRoleText } from "helpers/userRoleText"; +import { useRedux } from "hooks/useRedux"; +import { AppDispatch, resetStoreAction } from "store"; +import { + getOrgInfoAction, + updateOrgInfoAction, + clearErrorAction as orgClearErrorAction, + clearUpdateMessageAction as orgClearUpdateMessageAction, + getOrgLogoAction, +} from "store/ducks/organization"; +import { + clearErrorAction, + clearUpdateMessageAction, + getProfileInfoAction, + updateProfileInfoAction, +} from "store/ducks/profile"; +import { AccountProfile } from "types"; +import { useIsUserRoleAccepted } from "hooks/useIsUserRoleAccepted"; + +export const Profile = () => { + const { profile, organization } = useRedux("profile", "organization"); + const { isRoleAccepted } = useIsUserRoleAccepted([ + "owner", + "financial_controller", + ]); + + const [isEditAccount, setIsEditAccount] = useState(false); + const [isEditOrganization, setIsEditOrganization] = useState(false); + const [imageFile, setImageFile] = useState(); + const [imageFileUrl, setImageFileUrl] = useState(); + + const [accountDetails, setAccountDetails] = useState({ + firstName: "", + lastName: "", + email: "", + role: null, + }); + const [organizationDetails, setOrganizationDetails] = useState({ + name: "", + logo: "", + }); + + const dispatch: AppDispatch = useDispatch(); + const navigate = useNavigate(); + + useEffect(() => { + if (profile.updateMessage) { + setIsEditAccount(false); + dispatch(getProfileInfoAction()); + } + }, [profile.updateMessage, dispatch]); + + useEffect(() => { + if (organization.updateMessage) { + setIsEditOrganization(false); + setImageFile(undefined); + dispatch(getOrgInfoAction()); + dispatch(getOrgLogoAction()); + } + }, [organization.updateMessage, dispatch]); + + useEffect(() => { + if (imageFile) { + setImageFileUrl(URL.createObjectURL(imageFile)); + } + }, [imageFile]); + + useEffect(() => { + return () => { + if (imageFileUrl) { + URL.revokeObjectURL(imageFileUrl); + } + }; + }, [imageFileUrl]); + + useEffect(() => { + return () => { + dispatch(clearUpdateMessageAction()); + dispatch(orgClearUpdateMessageAction()); + }; + }, [dispatch]); + + const ImageUploadInput = ({ isReadOnly }: { isReadOnly?: boolean }) => { + const getInfoMessage = () => { + if (isReadOnly) { + return organization.data.name; + } + + return imageFile + ? imageFile.name + : "Drop your file here or click the button"; + }; + + const getDisplayImage = () => { + if (isReadOnly) { + return ( +
+ ); + } + + return imageFile ? ( +
+ ) : null; + }; + + return ( +
+ + + + + +
+ ) + } + onChange={handleImageUploadChange} + acceptedType={["image/png", "image/jpeg"]} + infoMessage={getInfoMessage()} + disabled={Boolean(isReadOnly)} + extraInfo={ +
+ {getDisplayImage()} +
+ } + /> + + ); + }; + + const emptyValueIfNotChanged = (newValue: string, oldValue: string) => { + return newValue === oldValue ? "" : newValue; + }; + + const handleAccountEditSubmit = (event: React.FormEvent) => { + event.preventDefault(); + + const { firstName, lastName, email } = accountDetails; + + if (firstName || lastName || email) { + dispatch( + // Don't submit values that haven't changed + updateProfileInfoAction({ + firstName: emptyValueIfNotChanged(firstName, profile.data.firstName), + lastName: emptyValueIfNotChanged(lastName, profile.data.lastName), + email: emptyValueIfNotChanged(email, profile.data.email), + }), + ); + } + }; + + const handleAccountEditCancel = (event: React.FormEvent) => { + event.preventDefault(); + setIsEditAccount(false); + setAccountDetails({ + firstName: profile.data.firstName, + lastName: profile.data.lastName, + email: profile.data.lastName, + role: profile.data.role, + }); + dispatch(clearErrorAction()); + }; + + const handleOrganizationEditSubmit = ( + event: React.FormEvent, + ) => { + event.preventDefault(); + + if (organizationDetails.name || imageFile) { + dispatch( + updateOrgInfoAction({ + name: emptyValueIfNotChanged( + organizationDetails.name, + organization.data.name, + ), + logo: imageFile, + }), + ); + } + }; + + const handleOrganizationEditCancel = ( + event: React.FormEvent, + ) => { + event.preventDefault(); + setIsEditOrganization(false); + setImageFile(undefined); + setOrganizationDetails({ + name: organization.data.name, + logo: organization.data.logo, + }); + dispatch(orgClearErrorAction()); + + if (imageFileUrl) { + URL.revokeObjectURL(imageFileUrl); + } + }; + + const handleAccountDetailsChange = ( + event: React.ChangeEvent, + ) => { + setAccountDetails({ + ...accountDetails, + [event.target.name]: event.target.value, + }); + }; + + const handleImageUploadChange = (file?: File) => { + setImageFile(file); + }; + + const handleOrgDetailsChange = ( + event: React.ChangeEvent, + ) => { + setOrganizationDetails({ + ...organizationDetails, + [event.target.name]: event.target.value, + }); + }; + + const handleSignOut = () => { + if (USE_SSO) { + // reset user store (from session storage) + singleUserStore().then(); + } + dispatch(resetStoreAction()); + localStorage.removeItem(LOCAL_STORAGE_SESSION_TOKEN); + }; + + const goToResetPassword = () => { + navigate(Routes.FORGOT_PASSWORD); + }; + + const renderAccount = () => { + const isSubmitDisabled = + accountDetails.firstName === profile.data.firstName && + accountDetails.lastName === profile.data.lastName && + accountDetails.email === profile.data.email; + + return ( +
+ {isEditAccount ? ( +
+
+ + + + +
+
+ ) : ( +
+
+
+ +
+ {profile.data.firstName} +
+
+ +
+ +
+ {profile.data.lastName} +
+
+ +
+ +
+ {profile.data.email} +
+
+ +
+ +
+ {userRoleText(profile.data.role)} +
+
+ +
+ +
+ Reset password +
+
+
+
+ )} + + {isEditAccount ? ( +
+ + +
+ ) : null} +
+ ); + }; + + const renderOrganization = () => { + return ( +
+
+
+ {isEditOrganization ? ( + <> + + + ) : ( + <> +
+ +
+ {organization.data.name} +
+
+ + )} + + +
+
+ + {isEditOrganization ? ( +
+ + +
+ ) : null} +
+ ); + }; + + return ( + <> + + + + + Profile + + + + + +
+ {profile.errorString ? ( + +
{profile.errorString}
+ {profile.errorExtras ? ( +
    + {Object.entries(profile.errorExtras).map(([key, value]) => ( +
  • {`${key}: ${value}`}
  • + ))} +
+ ) : null} +
+ ) : null} + + {organization.errorString ? ( + +
{organization.errorString}
+ {organization.errorExtras ? ( +
    + {Object.entries(organization.errorExtras).map( + ([key, value]) => ( +
  • {`${key}: ${value}`}
  • + ), + )} +
+ ) : null} +
+ ) : null} + + {profile.updateMessage || organization.updateMessage ? ( + { + dispatch(clearUpdateMessageAction()); + dispatch(orgClearUpdateMessageAction()); + }, + }, + ]} + > + {profile.updateMessage || organization.updateMessage} + + ) : null} + + +
+
+ + Personal details + + + {isEditAccount ? null : ( + }> + { + setIsEditAccount(true); + setAccountDetails({ + firstName: profile.data.firstName, + lastName: profile.data.lastName, + email: profile.data.email, + role: profile.data.role, + }); + }} + > + Edit details + + + )} +
+ + {renderAccount()} +
+
+ + +
+
+ + Organization + + + {!isRoleAccepted || isEditOrganization ? null : ( + }> + { + setIsEditOrganization(true); + setOrganizationDetails({ + name: organization.data.name, + logo: organization.data.logo, + }); + }} + > + Edit details + + + )} +
+ + {renderOrganization()} +
+
+ + +
+
Sign out
+ +
+
+ Click here to end your + session and sign out of the dashboard. +
+
+
+
+
+ + ); +}; diff --git a/src/pages/ReceiverDetails.tsx b/src/pages/ReceiverDetails.tsx new file mode 100644 index 0000000..f9dec19 --- /dev/null +++ b/src/pages/ReceiverDetails.tsx @@ -0,0 +1,541 @@ +import { useEffect, useState } from "react"; +import { useParams } from "react-router-dom"; +import { useDispatch } from "react-redux"; +import { + Card, + Heading, + Notification, + Profile, + Select, +} from "@stellar/design-system"; + +import { AppDispatch } from "store"; +import { getReceiverDetailsAction } from "store/ducks/receiverDetails"; +import { + getReceiverPaymentsAction, + getReceiverPaymentsWithParamsAction, +} from "store/ducks/receiverPayments"; +import { useRedux } from "hooks/useRedux"; +import { PAGE_LIMIT_OPTIONS, Routes } from "constants/settings"; + +import { Breadcrumbs } from "components/Breadcrumbs"; +import { SectionHeader } from "components/SectionHeader"; +import { CopyWithIcon } from "components/CopyWithIcon"; +import { AssetAmount } from "components/AssetAmount"; +import { InfoTooltip } from "components/InfoTooltip"; +import { PaymentsTable } from "components/PaymentsTable"; +import { Pagination } from "components/Pagination"; +import { ReceiverWalletBalance } from "components/ReceiverWalletBalance"; +import { ReceiverWalletHistory } from "components/ReceiverWalletHistory"; + +import { number, percent } from "helpers/formatIntlNumber"; +import { renderNumberOrDash } from "helpers/renderNumberOrDash"; +import { formatDateTime } from "helpers/formatIntlDateTime"; +import { shortenAccountKey } from "helpers/shortenAccountKey"; +import { ReceiverWallet } from "types"; + +export const ReceiverDetails = () => { + const { id: receiverId } = useParams(); + + const { receiverDetails, receiverPayments } = useRedux( + "receiverDetails", + "receiverPayments", + ); + + const [currentPage, setCurrentPage] = useState(1); + const [pageLimit, setPageLimit] = useState(20); + const [selectedWallet, setSelectedWallet] = useState(); + + const dispatch: AppDispatch = useDispatch(); + + const { stats } = receiverDetails; + const maxPages = receiverPayments.pagination?.pages || 1; + const defaultWallet = receiverDetails.wallets?.[0]; + + useEffect(() => { + if (receiverId) { + dispatch(getReceiverDetailsAction(receiverId)); + dispatch(getReceiverPaymentsAction(receiverId)); + } + }, [receiverId, dispatch]); + + useEffect(() => { + setSelectedWallet(defaultWallet); + }, [defaultWallet]); + + const calculateRate = () => { + if (stats?.paymentsSuccessfulCount && stats?.paymentsTotalCount) { + return Number(stats.paymentsSuccessfulCount / stats.paymentsTotalCount); + } + + return 0; + }; + + const handlePageLimitChange = ( + event: React.ChangeEvent, + ) => { + event.preventDefault(); + + const pageLimit = Number(event.target.value); + setPageLimit(pageLimit); + setCurrentPage(1); + + if (receiverId) { + // Need to make sure we'll be loading page 1 + dispatch( + getReceiverPaymentsWithParamsAction({ + receiver_id: receiverId, + page_limit: pageLimit.toString(), + page: "1", + }), + ); + } + }; + + const handlePageChange = (currentPage: number) => { + if (receiverId) { + dispatch( + getReceiverPaymentsWithParamsAction({ + receiver_id: receiverId, + page: currentPage.toString(), + }), + ); + } + }; + + const handleNextPage = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + const newPage = currentPage + 1; + + setCurrentPage(newPage); + handlePageChange(newPage); + }; + + const handlePrevPage = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + const newPage = currentPage - 1; + + setCurrentPage(newPage); + handlePageChange(newPage); + }; + + const setCardTemplateRows = (rows: number) => { + return { + "--StatCard-template-rows": rows, + } as React.CSSProperties; + }; + + const renderInfoCards = () => { + return ( +
+ +
+
+ +
+ +
+
+ +
+ +
+ {receiverDetails.orgId || "-"} +
+
+
+
+ +
+
+
+
+ + Successful payment rate + +
+ {/* TODO: add chart */} +
{`${percent.format( + calculateRate(), + )}`}
+
+
+ +
+
+ +
+ {renderNumberOrDash(receiverDetails.stats.paymentsTotalCount)} +
+
+ +
+ +
+ {renderNumberOrDash( + receiverDetails.stats.paymentsSuccessfulCount, + )} +
+
+ +
+ +
+ {renderNumberOrDash( + receiverDetails.stats.paymentsFailedCount, + )} +
+
+ +
+ +
+ {renderNumberOrDash( + receiverDetails.stats.paymentsRemainingCount, + )} +
+
+
+
+
+
+ ); + }; + + const renderTitle = ( + itemCount: number, + singularText: string, + pluralText: string, + ) => { + if (itemCount === 1) { + return `1 ${singularText}`; + } else if (itemCount > 1) { + return `${number.format(itemCount)} ${pluralText}`; + } + + return pluralText; + }; + + const renderWalletOptionText = (wallet: ReceiverWallet) => { + return `${wallet.provider} (${ + wallet.stellarAddress + ? shortenAccountKey(wallet.stellarAddress) + : "Unregistered" + })`; + }; + + const renderWallets = () => { + return ( +
+
+ + +
+ {renderTitle(receiverDetails.wallets.length, "wallet", "wallets")} +
+
+ + {selectedWallet ? ( + <> + +
+ {/* Column one */} +
+
+ +
+ +
+
+ +
+ +
+ {selectedWallet.stellarAddress ? ( + + ) : ( + "Unregistered" + )} +
+
+ +
+ +
+ {selectedWallet.provider || "-"} +
+
+
+ + {/* Column two */} +
+
+ +
+ {formatDateTime(selectedWallet.invitedAt)} +
+
+ +
+ +
+ {formatDateTime(selectedWallet.createdAt)} +
+
+ +
+ +
+ {formatDateTime(selectedWallet.smsLastSentAt)} +
+
+
+ + {/* Column three */} +
+
+ +
+ {renderNumberOrDash(selectedWallet.totalPaymentsCount)} +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+
+
+
+ +
+ + + + + Recent wallet history + + + + + + +
+ + ) : null} +
+ ); + }; + + const renderContent = () => { + if (receiverDetails.errorString) { + return ( + + {receiverDetails.errorString} + + ); + } + + if (!receiverId || !receiverDetails.id) { + return null; + } + + return ( + <> +
+ + + + + + {receiverDetails.phoneNumber} + + + + + + + {renderInfoCards()} +
+ +
+ + + + + Wallets + + + + + + {renderWallets()} +
+ +
+ + + + + {renderTitle( + receiverPayments.pagination?.total || 0, + "Payment", + "Payments", + )} + + + + +
+ +
+ + { + event.preventDefault(); + setCurrentPage(Number(event.target.value)); + }} + onBlur={handlePageChange} + onNext={handleNextPage} + onPrevious={handlePrevPage} + isLoading={receiverPayments.status === "PENDING"} + /> +
+
+
+ + +
+ + ); + }; + + return ( + <> + + + {renderContent()} + + ); +}; diff --git a/src/pages/Receivers.tsx b/src/pages/Receivers.tsx new file mode 100644 index 0000000..b6244f4 --- /dev/null +++ b/src/pages/Receivers.tsx @@ -0,0 +1,300 @@ +import { useState, useEffect } from "react"; +import { useDispatch } from "react-redux"; +import { useNavigate } from "react-router-dom"; +import { Button, Heading, Icon, Input, Select } from "@stellar/design-system"; + +import { FilterMenu } from "components/FilterMenu"; +import { SearchInput } from "components/SearchInput"; +import { SectionHeader } from "components/SectionHeader"; +import { Pagination } from "components/Pagination"; +import { ReceiversTable } from "components/ReceiversTable"; + +import { PAGE_LIMIT_OPTIONS, Routes } from "constants/settings"; +import { number } from "helpers/formatIntlNumber"; +import { useRedux } from "hooks/useRedux"; +import { AppDispatch } from "store"; +import { + getReceiversAction, + getReceiversWithParamsAction, +} from "store/ducks/receivers"; +import { CommonFilters, SortByReceivers, SortDirection } from "types"; + +export const Receivers = () => { + const { receivers } = useRedux("receivers"); + + const [currentPage, setCurrentPage] = useState(1); + const [pageLimit, setPageLimit] = useState(20); + + const initFilters: CommonFilters = { + status: "", + created_at_after: "", + created_at_before: "", + }; + + const [filters, setFilters] = useState(initFilters); + + const isFiltersSelected = + Object.values(filters).filter((v) => Boolean(v)).length > 0; + + const dispatch: AppDispatch = useDispatch(); + const navigate = useNavigate(); + + useEffect(() => { + dispatch(getReceiversAction()); + }, [dispatch]); + + const apiError = receivers.status === "ERROR" && receivers.errorString; + const maxPages = receivers.pagination?.pages || 1; + const isSearchInProgress = Boolean( + receivers.searchParams?.q && receivers.status === "PENDING", + ); + + const handleSearchChange = (searchText?: string) => { + dispatch( + getReceiversWithParamsAction({ + page: "1", + ...filters, + q: searchText, + }), + ); + + setCurrentPage(1); + }; + + const handleFilterChange = ( + event: React.ChangeEvent, + ) => { + setFilters({ + ...filters, + [event.target.id]: event.target.value, + }); + }; + + const handleFilterSubmit = () => { + dispatch( + getReceiversWithParamsAction({ + page: "1", + ...filters, + }), + ); + + setCurrentPage(1); + }; + + const handleFilterReset = () => { + dispatch( + getReceiversWithParamsAction({ + page: "1", + ...initFilters, + }), + ); + + setFilters(initFilters); + setCurrentPage(1); + }; + + const handleSort = (sort?: SortByReceivers, direction?: SortDirection) => { + if (!sort || !direction || direction === "default") { + dispatch( + getReceiversWithParamsAction({ + page: "1", + sort: undefined, + direction: undefined, + }), + ); + } else { + dispatch( + getReceiversWithParamsAction({ + page: "1", + sort, + direction, + }), + ); + } + + setCurrentPage(1); + }; + + const handleExport = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + alert("TODO: handle export"); + }; + + const handlePageLimitChange = ( + event: React.ChangeEvent, + ) => { + event.preventDefault(); + + const pageLimit = Number(event.target.value); + setPageLimit(pageLimit); + setCurrentPage(1); + + // Need to make sure we'll be loading page 1 + dispatch( + getReceiversWithParamsAction({ + page_limit: pageLimit.toString(), + page: "1", + }), + ); + }; + + const handlePageChange = (currentPage: number) => { + dispatch(getReceiversWithParamsAction({ page: currentPage.toString() })); + }; + + const handleNextPage = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + const newPage = currentPage + 1; + + setCurrentPage(newPage); + handlePageChange(newPage); + }; + + const handlePrevPage = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + const newPage = currentPage - 1; + + setCurrentPage(newPage); + handlePageChange(newPage); + }; + + const handleReceiverClicked = ( + event: React.MouseEvent, + receiverId: string, + ) => { + event.preventDefault(); + navigate(`${Routes.RECEIVERS}/${receiverId}`); + }; + + return ( + <> + + + + + {receivers.pagination?.total && receivers.pagination.total > 0 + ? `${number.format(receivers.pagination.total)} ` + : ""} + Receivers + + + + + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+ + +
+ + +
+ +
+ + { + event.preventDefault(); + setCurrentPage(Number(event.target.value)); + }} + onBlur={handlePageChange} + onNext={handleNextPage} + onPrevious={handlePrevPage} + isLoading={receivers.status === "PENDING"} + /> +
+
+
+ + + + ); +}; diff --git a/src/pages/Redirect.tsx b/src/pages/Redirect.tsx new file mode 100644 index 0000000..6b43acf --- /dev/null +++ b/src/pages/Redirect.tsx @@ -0,0 +1,18 @@ +import { useDispatch } from "react-redux"; +import { useNavigate } from "react-router-dom"; +import { useEffect } from "react"; +import { AppDispatch } from "store"; +import { singleSignOnAction } from "store/ducks/singleSignOnUserAccount"; + +export function SigninOidc() { + const dispatch: AppDispatch = useDispatch(); + const navigate = useNavigate(); + + useEffect(() => { + dispatch(singleSignOnAction()).finally(() => { + navigate("/"); + }); + }, [dispatch, navigate]); + + return
Redirecting...
; +} diff --git a/src/pages/ResetPassword.tsx b/src/pages/ResetPassword.tsx new file mode 100644 index 0000000..0912b60 --- /dev/null +++ b/src/pages/ResetPassword.tsx @@ -0,0 +1,199 @@ +import { useEffect, useState } from "react"; +import { + Heading, + Input, + Button, + Notification, + Link, +} from "@stellar/design-system"; +import { useDispatch } from "react-redux"; +import { useNavigate } from "react-router-dom"; + +import { AppDispatch } from "store"; +import { + resetForgotPasswordAction, + resetPasswordAction, +} from "store/ducks/forgotPassword"; +import { useRedux } from "hooks/useRedux"; + +export const ResetPassword = () => { + const dispatch: AppDispatch = useDispatch(); + const navigate = useNavigate(); + + const { forgotPassword } = useRedux("forgotPassword"); + + const [password, setPassword] = useState(""); + const [confirmPassword, setConfirmPassword] = useState(""); + const [confirmationToken, setConfirmationToken] = useState(""); + + const [errorPassword, setErrorPassword] = useState(""); + const [errorPasswordMatch, setErrorPasswordMatch] = useState(""); + const [errorConfirmationToken, setErrorConfirmationToken] = useState(""); + + const handleResetPassword = (event: React.FormEvent) => { + event.preventDefault(); + dispatch(resetPasswordAction({ password, confirmationToken })); + }; + + useEffect(() => { + if (forgotPassword.status === "SUCCESS") { + setPassword(""); + setConfirmPassword(""); + setConfirmationToken(""); + } + }, [forgotPassword.status]); + + const goToSignIn = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + dispatch(resetForgotPasswordAction()); + navigate("/"); + }; + + const validatePassword = () => { + const passwordStrength = new RegExp( + "^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*])(?=.{8,})", + ); + + let errorMsg = ""; + + if (!password) { + errorMsg = "Password is required"; + } else if (password.length < 8) { + errorMsg = "Password must be at least 8 characters long"; + } else if (!passwordStrength.test(password)) { + errorMsg = + "Password must have at least one uppercase letter, lowercase letter, number, and symbol."; + } + + setErrorPassword(errorMsg); + + if (confirmPassword) { + validatePasswordMatch(); + } + }; + + const validatePasswordMatch = () => { + if (confirmPassword) { + setErrorPasswordMatch( + password === confirmPassword ? "" : "Passwords don't match", + ); + } else { + setErrorPasswordMatch("Confirm password is required"); + } + }; + + const validateConfirmationToken = () => { + setErrorConfirmationToken( + confirmationToken ? "" : "Confirmation token is required", + ); + }; + + const allInputsValid = () => { + if (errorPassword || errorPasswordMatch || errorConfirmationToken) { + return false; + } else if (password && confirmPassword && confirmationToken) { + return true; + } + + return false; + }; + + return ( + <> +
+ {forgotPassword.status === "SUCCESS" && ( + + Password reset successfully. You can{" "} + sign in using your new password. + + )} + + {forgotPassword.errorString && ( + + {forgotPassword.errorString}. Check your email for the correct + token. + + )} + +
+
+ + Reset password + + +
+ New password must be: +
    +
  • at least 8 characters long,
  • +
  • + a combination of uppercase letters, lowercase letters, + numbers, and symbols. +
  • +
+
+
+ + { + setErrorConfirmationToken(""); + setConfirmationToken(e.target.value); + }} + onBlur={validateConfirmationToken} + value={confirmationToken} + error={errorConfirmationToken} + /> + + { + setErrorPassword(""); + setPassword(e.target.value); + }} + onBlur={validatePassword} + value={password} + isPassword + error={errorPassword} + /> + + { + setErrorPasswordMatch(""); + setConfirmPassword(e.target.value); + }} + onBlur={validatePasswordMatch} + value={confirmPassword} + isPassword + error={errorPasswordMatch} + /> + + + + + Sign in + +
+
+ + ); +}; diff --git a/src/pages/Settings.tsx b/src/pages/Settings.tsx new file mode 100644 index 0000000..dfab921 --- /dev/null +++ b/src/pages/Settings.tsx @@ -0,0 +1,117 @@ +import { useDispatch } from "react-redux"; +import { Heading, Notification } from "@stellar/design-system"; + +import { SectionHeader } from "components/SectionHeader"; +import { NotificationWithButtons } from "components/NotificationWithButtons"; +import { SettingsTeamMembers } from "components/SettingsTeamMembers"; + +import { AppDispatch } from "store"; +import { resetNewUserAction, resetUpdatedUserAction } from "store/ducks/users"; +import { useRedux } from "hooks/useRedux"; +import { userRoleText } from "helpers/userRoleText"; + +export const Settings = () => { + const { users } = useRedux("users"); + + const dispatch: AppDispatch = useDispatch(); + + const getUserNameText = (firstName?: string, lastName?: string) => { + if (firstName || lastName) { + return `${firstName} ${lastName}`; + } + + return "this user"; + }; + + const renderUpdateUserSuccessMessage = () => { + const user = users.items.find((u) => u.id === users.updatedUser.id); + + if (users.updatedUser.actionType === "status") { + return `Account of ${getUserNameText( + user?.first_name, + user?.last_name, + )} was updated successfully. New status is ${ + users.updatedUser.is_active ? "active" : "inactive" + }.`; + } + + if (users.updatedUser.actionType === "role") { + return `Account of ${getUserNameText( + user?.first_name, + user?.last_name, + )} was updated successfully. New role is ${userRoleText( + users.updatedUser.role, + )}.`; + } + + return "Account was updated successfully."; + }; + + return ( + <> + + + + + Settings + + + + + +
+ {users.updatedUser.status === "SUCCESS" ? ( + { + dispatch(resetUpdatedUserAction()); + }, + }, + ]} + > + {renderUpdateUserSuccessMessage()} + + ) : null} + + {users.newUser.status === "SUCCESS" ? ( + { + dispatch(resetNewUserAction()); + }, + }, + ]} + > + {`Team member ${users.newUser.first_name} ${ + users.newUser.last_name + } with role ${userRoleText( + users.newUser.role, + )} was added successfully.`} + + ) : null} + + {users.updatedUser.errorString || users.newUser.errorString ? ( + + {users.updatedUser.errorString || users.newUser.errorString} + + ) : null} + + {users.errorString ? ( + + {users.errorString} + + ) : ( + + )} +
+ + ); +}; diff --git a/src/pages/SignIn.tsx b/src/pages/SignIn.tsx new file mode 100644 index 0000000..7bc68b8 --- /dev/null +++ b/src/pages/SignIn.tsx @@ -0,0 +1,189 @@ +import { useEffect, useState, useRef } from "react"; +import Recaptcha from "react-google-recaptcha"; +import { + Heading, + Input, + Button, + Notification, + Link, +} from "@stellar/design-system"; +import { useDispatch } from "react-redux"; +import { useNavigate, useLocation } from "react-router-dom"; +import { v4 as uuidv4 } from "uuid"; + +import { AppDispatch, resetStoreAction } from "store"; +import { signInAction } from "store/ducks/userAccount"; +import { + Routes, + USE_SSO, + RECAPTCHA_SITE_KEY, + LOCAL_STORAGE_DEVICE_ID, +} from "constants/settings"; +import { useRedux } from "hooks/useRedux"; +import { signInRedirect } from "helpers/singleSingOn"; + +export const SignIn = () => { + const dispatch: AppDispatch = useDispatch(); + const navigate = useNavigate(); + const location = useLocation(); + const recaptchaRef = useRef(null); + + const { userAccount } = useRedux("userAccount"); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [recaptchaToken, setRecaptchaToken] = useState(""); + const [deviceId, setDeviceId] = useState(""); + + const isSessionExpired = userAccount.isSessionExpired; + + useEffect(() => { + const storedDeviceId = localStorage.getItem(LOCAL_STORAGE_DEVICE_ID); + if (!storedDeviceId) { + const newDeviceId = uuidv4(); + localStorage.setItem(LOCAL_STORAGE_DEVICE_ID, newDeviceId); + setDeviceId(newDeviceId); + } else { + setDeviceId(storedDeviceId); + } + }, [deviceId]); + + useEffect(() => { + if (userAccount.isAuthenticated && userAccount.needsMFA) { + navigate( + { + pathname: Routes.MFA, + search: location.search, + }, + { state: { email, password } }, + ); + } + }, [ + location.search, + navigate, + userAccount.restoredPathname, + userAccount.isAuthenticated, + userAccount.needsMFA, + email, + password, + ]); + + useEffect(() => { + if (userAccount.isAuthenticated && !userAccount.needsMFA) { + navigate({ + pathname: userAccount.restoredPathname ?? Routes.HOME, + search: location.search, + }); + } + }, [ + location.search, + navigate, + userAccount.isAuthenticated, + userAccount.restoredPathname, + userAccount.needsMFA, + ]); + + const handleSubmit = (event: React.FormEvent) => { + event.preventDefault(); + dispatch(resetStoreAction()); + + const headers = { + "Device-ID": deviceId, + }; + + dispatch(signInAction({ email, password, recaptchaToken, headers })); + recaptchaRef.current?.reset(); + }; + + const onRecaptchaSubmit = (token: string | null) => { + if (token) { + setRecaptchaToken(token); + } + }; + + const goToForgotPassword = ( + event: React.MouseEvent, + ) => { + event.preventDefault(); + navigate(Routes.FORGOT_PASSWORD); + }; + + return ( + <> +
+ {isSessionExpired && ( + + )} + {!isSessionExpired && userAccount.errorString && ( + + {userAccount.errorString} + + )} + +
+ + Sign in to Stellar Disbursement Platform + + {!USE_SSO && ( + <> + setEmail(e.target.value)} + type="email" + /> + setPassword(e.target.value)} + /> + + + )} + {USE_SSO ? ( + + ) : ( + + )} + + + Forgot Password? + + +
+ + ); +}; diff --git a/src/pages/Unauthorized.tsx b/src/pages/Unauthorized.tsx new file mode 100644 index 0000000..a6560b0 --- /dev/null +++ b/src/pages/Unauthorized.tsx @@ -0,0 +1,15 @@ +import { Heading, Paragraph } from "@stellar/design-system"; + +export const Unauthorized = () => { + return ( + <> + + Unauthorized + + + You are not authorized to view this feature. Please contact your + administrator with questions. + + + ); +}; diff --git a/src/pages/Wallets.tsx b/src/pages/Wallets.tsx new file mode 100644 index 0000000..4bd4a34 --- /dev/null +++ b/src/pages/Wallets.tsx @@ -0,0 +1,109 @@ +import { Fragment } from "react"; +import { + Card, + Heading, + Profile, + Title, + Notification, +} from "@stellar/design-system"; +import { useDispatch } from "react-redux"; +import { InfoTooltip } from "components/InfoTooltip"; +import { SectionHeader } from "components/SectionHeader"; +import { AccountBalances } from "components/AccountBalances"; +import { WalletTrustlines } from "components/WalletTrustlines"; +import { useRedux } from "hooks/useRedux"; +import { useOrgAccountInfo } from "hooks/useOrgAccountInfo"; +import { AppDispatch } from "store"; +import { getStellarAccountAction } from "store/ducks/organization"; + +export const Wallets = () => { + const { organization } = useRedux("organization"); + const { assetBalances, distributionAccountPublicKey } = organization.data; + + useOrgAccountInfo(distributionAccountPublicKey); + + const dispatch: AppDispatch = useDispatch(); + + const renderContent = () => { + if (organization.errorString) { + return ( + + {organization.errorString} + + ); + } + + if (!assetBalances || assetBalances.length === 0) { + return
There are no distribution accounts
; + } + + return ( + <> +
+ +
+ Add funds to your distribution account by sending Stellar-based + digital assets to the public key above. +
+
+ Make sure your account has a trustline to the asset before you send + funds. +
+
+ +
+ Current balance: + + <> + {assetBalances.map((a) => ( + + {} + + ))} + +
+ + ); + }; + + return ( + <> + + + + + Wallets + + + + + +
+ +
+
+ + Distribution account public key + +
+ + {renderContent()} +
+
+ + {/* TODO: hard-coded to a single wallet, figure out how to handle multiple */} + { + dispatch(getStellarAccountAction(distributionAccountPublicKey)); + }} + /> +
+ + ); +}; diff --git a/src/setupTests.ts b/src/setupTests.ts new file mode 100644 index 0000000..1dd407a --- /dev/null +++ b/src/setupTests.ts @@ -0,0 +1,5 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import "@testing-library/jest-dom"; diff --git a/src/store/ducks/assets.ts b/src/store/ducks/assets.ts new file mode 100644 index 0000000..56f7e37 --- /dev/null +++ b/src/store/ducks/assets.ts @@ -0,0 +1,59 @@ +import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { RootState } from "store"; +import { getAssets } from "api/getAssets"; +import { handleApiErrorString } from "api/handleApiErrorString"; +import { endSessionIfTokenInvalid } from "helpers/endSessionIfTokenInvalid"; +import { ApiAsset, ApiError, AssetsInitialState, RejectMessage } from "types"; + +export const getAssetsAction = createAsyncThunk< + ApiAsset[], + undefined, + { rejectValue: RejectMessage; state: RootState } +>( + "assets/getAssetsAction", + async (_, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + + try { + const assets = await getAssets(token); + // Don't show soft-deleted assets + return assets.filter((a) => !a.deleted_at); + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching assets: ${errorString}`, + }); + } + }, +); + +const initialState: AssetsInitialState = { + items: [], + status: undefined, + errorString: undefined, +}; + +const assetsSlice = createSlice({ + name: "assets", + initialState, + reducers: {}, + extraReducers: (builder) => { + builder.addCase(getAssetsAction.pending, (state = initialState) => { + state.status = "PENDING"; + }); + builder.addCase(getAssetsAction.fulfilled, (state, action) => { + state.items = action.payload; + state.status = "SUCCESS"; + state.errorString = undefined; + }); + builder.addCase(getAssetsAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + }, +}); + +export const assetsSelector = (state: RootState) => state.assets; +export const { reducer } = assetsSlice; diff --git a/src/store/ducks/countries.ts b/src/store/ducks/countries.ts new file mode 100644 index 0000000..a58eb1a --- /dev/null +++ b/src/store/ducks/countries.ts @@ -0,0 +1,63 @@ +import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { RootState } from "store"; +import { getCountries } from "api/getCountries"; +import { handleApiErrorString } from "api/handleApiErrorString"; +import { endSessionIfTokenInvalid } from "helpers/endSessionIfTokenInvalid"; +import { + ApiCountry, + ApiError, + CountriesInitialState, + RejectMessage, +} from "types"; + +export const getCountriesAction = createAsyncThunk< + ApiCountry[], + undefined, + { rejectValue: RejectMessage; state: RootState } +>( + "countries/getCountriesAction", + async (_, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + + try { + const countries = await getCountries(token); + return countries; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching countries: ${errorString}`, + }); + } + }, +); + +const initialState: CountriesInitialState = { + items: [], + status: undefined, + errorString: undefined, +}; + +const countriesSlice = createSlice({ + name: "countries", + initialState, + reducers: {}, + extraReducers: (builder) => { + builder.addCase(getCountriesAction.pending, (state = initialState) => { + state.status = "PENDING"; + }); + builder.addCase(getCountriesAction.fulfilled, (state, action) => { + state.items = action.payload; + state.status = "SUCCESS"; + state.errorString = undefined; + }); + builder.addCase(getCountriesAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + }, +}); + +export const countriesSelector = (state: RootState) => state.countries; +export const { reducer } = countriesSlice; diff --git a/src/store/ducks/disbursementDetails.ts b/src/store/ducks/disbursementDetails.ts new file mode 100644 index 0000000..9315ba5 --- /dev/null +++ b/src/store/ducks/disbursementDetails.ts @@ -0,0 +1,261 @@ +import { PayloadAction, createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { RootState } from "store"; +import { getDisbursementDetails } from "api/getDisbursementDetails"; +import { getDisbursementReceivers } from "api/getDisbursementReceivers"; +import { handleApiErrorString } from "api/handleApiErrorString"; +import { patchDisbursementStatus } from "api/patchDisbursementStatus"; +import { endSessionIfTokenInvalid } from "helpers/endSessionIfTokenInvalid"; +import { refreshSessionToken } from "helpers/refreshSessionToken"; +import { formatDisbursement } from "helpers/formatDisbursements"; +import { + ApiDisbursementReceiver, + ApiDisbursementReceivers, + ApiError, + Disbursement, + DisbursementDetailsInitialState, + DisbursementDraft, + DisbursementReceiver, + DisbursementStatus, + PaginationParams, + RejectMessage, +} from "types"; + +export const getDisbursementDetailsAction = createAsyncThunk< + Disbursement, + string, + { rejectValue: RejectMessage; state: RootState } +>( + "disbursementDetails/getDisbursementDetailsAction", + async (disbursementId, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + + try { + const disbursementDetails = await getDisbursementDetails( + token, + disbursementId, + ); + refreshSessionToken(dispatch); + + return formatDisbursement(disbursementDetails); + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching disbursement details: ${errorString}`, + }); + } + }, +); + +export const getDisbursementReceiversAction = createAsyncThunk< + { + receivers: ApiDisbursementReceivers; + searchParams?: PaginationParams; + }, + PaginationParams | undefined, + { rejectValue: RejectMessage; state: RootState } +>( + "disbursementDetails/getDisbursementReceiversAction", + async (params, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + const { id, receivers } = getState().disbursementDetails.details; + + const newParams = { ...receivers?.searchParams, ...params }; + + try { + const receivers = await getDisbursementReceivers(token, id, newParams); + refreshSessionToken(dispatch); + + return { + receivers: receivers, + searchParams: newParams, + }; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching disbursement receivers: ${errorString}`, + }); + } + }, +); + +export const pauseOrStartDisbursementAction = createAsyncThunk< + { status: DisbursementStatus; message: string }, + DisbursementStatus, + { rejectValue: RejectMessage; state: RootState } +>( + "disbursementDetails/pauseOrStartDisbursementAction", + async (newStatus, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + const { id } = getState().disbursementDetails.details; + + try { + const { message } = await patchDisbursementStatus(token, id, newStatus); + refreshSessionToken(dispatch); + + return { status: newStatus, message }; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error ${ + newStatus === "PAUSED" ? "starting" : "pausing" + } the disbursement: ${errorString}`, + }); + } + }, +); + +const initialState: DisbursementDetailsInitialState = { + details: { + id: "", + name: "", + createdAt: "", + stats: { + paymentsSuccessfulCount: 0, + paymentsFailedCount: 0, + paymentsRemainingCount: 0, + paymentsTotalCount: 0, + totalAmount: "", + disbursedAmount: "", + averagePaymentAmount: "", + }, + asset: { + code: "", + id: "", + }, + country: { + code: "", + name: "", + }, + wallet: { + id: "", + name: "", + }, + receivers: { + items: [], + pagination: undefined, + searchParams: undefined, + }, + status: "DRAFT", + fileName: undefined, + }, + instructions: { + csvName: undefined, + csvFile: undefined, + }, + status: undefined, + errorString: undefined, +}; + +const disbursementDetailsSlice = createSlice({ + name: "disbursementDetails", + initialState, + reducers: { + setDisbursementDetailsAction: ( + state, + action: PayloadAction, + ) => { + state.details = action.payload.details; + state.instructions = action.payload.instructions; + state.status = "SUCCESS"; + state.errorString = undefined; + }, + resetDisbursementDetailsAction: () => initialState, + }, + extraReducers: (builder) => { + // Get disbursement details + builder.addCase( + getDisbursementDetailsAction.pending, + (state = initialState) => { + state.status = "PENDING"; + }, + ); + builder.addCase(getDisbursementDetailsAction.fulfilled, (state, action) => { + state.details = action.payload; + state.status = "SUCCESS"; + state.errorString = undefined; + }); + builder.addCase(getDisbursementDetailsAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + // Get disbursement receivers + builder.addCase( + getDisbursementReceiversAction.pending, + (state = initialState) => { + state.status = "PENDING"; + }, + ); + builder.addCase( + getDisbursementReceiversAction.fulfilled, + (state, action) => { + state.details.receivers = { + items: formatDisbursementReceivers(action.payload.receivers.data), + pagination: action.payload.receivers.pagination, + searchParams: action.payload.searchParams, + }; + state.status = "SUCCESS"; + state.errorString = undefined; + }, + ); + builder.addCase( + getDisbursementReceiversAction.rejected, + (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }, + ); + // Pause or start disbursement + builder.addCase( + pauseOrStartDisbursementAction.pending, + (state = initialState) => { + state.status = "PENDING"; + }, + ); + builder.addCase( + pauseOrStartDisbursementAction.fulfilled, + (state, action) => { + state.details = { + ...state.details, + status: action.payload.status, + }; + state.status = "SUCCESS"; + state.errorString = undefined; + }, + ); + builder.addCase( + pauseOrStartDisbursementAction.rejected, + (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }, + ); + }, +}); + +export const disbursementDetailsSelector = (state: RootState) => + state.disbursementDetails; +export const { reducer } = disbursementDetailsSlice; +export const { setDisbursementDetailsAction, resetDisbursementDetailsAction } = + disbursementDetailsSlice.actions; + +const formatDisbursementReceivers = ( + items: ApiDisbursementReceiver[], +): DisbursementReceiver[] => + items.map((r) => ({ + id: r.id, + phoneNumber: r.phone_number, + provider: r.receiver_wallet.wallet.name, + amount: r.payment.amount, + assetCode: r.payment.asset.code, + completedAt: + r.payment.status === "SUCCESS" ? r.payment.updated_at : undefined, + blockchainId: r.payment.stellar_transaction_id, + orgId: r.external_id, + paymentStatus: r.payment.status, + })); diff --git a/src/store/ducks/disbursementDrafts.ts b/src/store/ducks/disbursementDrafts.ts new file mode 100644 index 0000000..b996d55 --- /dev/null +++ b/src/store/ducks/disbursementDrafts.ts @@ -0,0 +1,236 @@ +import { PayloadAction, createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { RootState } from "store"; +import { getDisbursementDrafts } from "api/getDisbursementDrafts"; +import { postDisbursement } from "api/postDisbursement"; +import { postDisbursementFile } from "api/postDisbursementFile"; +import { patchDisbursementStatus } from "api/patchDisbursementStatus"; +import { handleApiErrorString } from "api/handleApiErrorString"; +import { formatDisbursement } from "helpers/formatDisbursements"; +import { endSessionIfTokenInvalid } from "helpers/endSessionIfTokenInvalid"; +import { refreshSessionToken } from "helpers/refreshSessionToken"; +import { + ApiError, + Disbursement, + DisbursementDraft, + DisbursementDraftRejectMessage, + DisbursementDraftsInitialState, + Pagination, + RejectMessage, +} from "types"; + +export const getDisbursementDraftsAction = createAsyncThunk< + { + items: DisbursementDraft[]; + pagination: Pagination; + }, + undefined, + { rejectValue: RejectMessage; state: RootState } +>( + "disbursementDrafts/getDisbursementDraftsAction", + async (_, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + + try { + const { data, pagination } = await getDisbursementDrafts(token); + refreshSessionToken(dispatch); + + return { + items: data.map((d) => ({ + details: formatDisbursement(d), + // TODO: get instructions once we have them in response + instructions: { + csvFile: undefined, + csvName: undefined, + }, + })), + pagination, + }; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching drafts: ${errorString}`, + }); + } + }, +); + +export const saveDisbursementDraftAction = createAsyncThunk< + string, + { + details: Disbursement; + file?: File; + }, + { rejectValue: DisbursementDraftRejectMessage; state: RootState } +>( + "disbursementDrafts/saveDisbursementDraftAction", + async ({ details, file }, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + const { newDraftId } = getState().disbursementDrafts; + + let draftId; + + try { + draftId = newDraftId ?? (await postDisbursement(token, details)).id; + + if (file) { + await postDisbursementFile(token, draftId, file); + refreshSessionToken(dispatch); + + return draftId; + } else { + refreshSessionToken(dispatch); + + return draftId; + } + } catch (error: unknown) { + const err = error as ApiError; + const errorString = handleApiErrorString(err); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error saving draft: ${errorString}`, + errorExtras: err?.extras, + // Need to save draft ID if it failed because of CSV upload + newDraftId: draftId, + }); + } + }, +); + +export const submitDisbursementDraftAction = createAsyncThunk< + string, + { + details: Disbursement; + file: File; + }, + { rejectValue: DisbursementDraftRejectMessage; state: RootState } +>( + "disbursementDrafts/submitDisbursementDraftAction", + async ({ details, file }, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + const { newDraftId } = getState().disbursementDrafts; + let draftId; + + try { + draftId = newDraftId ?? (await postDisbursement(token, details)).id; + await postDisbursementFile(token, draftId, file); + await patchDisbursementStatus(token, draftId, "STARTED"); + refreshSessionToken(dispatch); + + return draftId; + } catch (error: unknown) { + const err = error as ApiError; + const errorString = handleApiErrorString(err); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error submitting disbursement: ${errorString}`, + errorExtras: err?.extras, + // Need to save draft ID if it failed because of CSV upload + newDraftId: draftId, + }); + } + }, +); + +const initialState: DisbursementDraftsInitialState = { + items: [], + status: undefined, + newDraftId: undefined, + pagination: undefined, + errorString: undefined, + errorExtras: undefined, + actionType: undefined, +}; + +const disbursementDraftsSlice = createSlice({ + name: "disbursementDrafts", + initialState, + reducers: { + resetDisbursementDraftsAction: () => initialState, + clearDisbursementDraftsErrorAction: (state) => { + state.errorString = undefined; + state.errorExtras = undefined; + state.status = "SUCCESS"; + state.actionType = undefined; + }, + setDraftIdAction: (state, action: PayloadAction) => { + state.newDraftId = action.payload; + }, + }, + extraReducers: (builder) => { + // Get disbursement drafts + builder.addCase( + getDisbursementDraftsAction.pending, + (state = initialState) => { + state.status = "PENDING"; + }, + ); + builder.addCase(getDisbursementDraftsAction.fulfilled, (state, action) => { + state.items = action.payload.items; + state.pagination = action.payload.pagination; + state.status = "SUCCESS"; + state.newDraftId = undefined; + state.errorString = undefined; + state.errorExtras = undefined; + state.actionType = undefined; + }); + builder.addCase(getDisbursementDraftsAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + // Save disbursement draft + builder.addCase( + saveDisbursementDraftAction.pending, + (state = initialState) => { + state.status = "PENDING"; + state.actionType = "save"; + }, + ); + builder.addCase(saveDisbursementDraftAction.fulfilled, (state, action) => { + state.newDraftId = action.payload; + state.status = "SUCCESS"; + state.errorString = undefined; + state.errorExtras = undefined; + }); + builder.addCase(saveDisbursementDraftAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + state.errorExtras = action.payload?.errorExtras; + state.newDraftId = action.payload?.newDraftId; + }); + // Submit disbursement + builder.addCase( + submitDisbursementDraftAction.pending, + (state = initialState) => { + state.status = "PENDING"; + state.actionType = "submit"; + }, + ); + builder.addCase( + submitDisbursementDraftAction.fulfilled, + (state, action) => { + state.newDraftId = action.payload; + state.status = "SUCCESS"; + state.errorString = undefined; + }, + ); + builder.addCase(submitDisbursementDraftAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + state.errorExtras = action.payload?.errorExtras; + state.newDraftId = action.payload?.newDraftId; + }); + }, +}); + +export const disbursementDraftsSelector = (state: RootState) => + state.disbursementDrafts; +export const { reducer } = disbursementDraftsSlice; +export const { + resetDisbursementDraftsAction, + clearDisbursementDraftsErrorAction, + setDraftIdAction, +} = disbursementDraftsSlice.actions; diff --git a/src/store/ducks/disbursements.ts b/src/store/ducks/disbursements.ts new file mode 100644 index 0000000..df5f8e6 --- /dev/null +++ b/src/store/ducks/disbursements.ts @@ -0,0 +1,131 @@ +import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { RootState } from "store"; +import { getDisbursements } from "api/getDisbursements"; +import { handleApiErrorString } from "api/handleApiErrorString"; +import { formatDisbursements } from "helpers/formatDisbursements"; +import { endSessionIfTokenInvalid } from "helpers/endSessionIfTokenInvalid"; +import { refreshSessionToken } from "helpers/refreshSessionToken"; +import { + ApiDisbursements, + ApiError, + DisbursementsInitialState, + DisbursementsSearchParams, + RejectMessage, +} from "types"; + +export const getDisbursementsAction = createAsyncThunk< + ApiDisbursements, + undefined, + { rejectValue: RejectMessage; state: RootState } +>( + "disbursements/getDisbursementsAction", + async (_, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + + try { + const disbursements = await getDisbursements(token); + refreshSessionToken(dispatch); + + return disbursements; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching disbursements: ${errorString}`, + }); + } + }, +); + +export const getDisbursementsWithParamsAction = createAsyncThunk< + { + disbursements: ApiDisbursements; + searchParams: DisbursementsSearchParams; + }, + DisbursementsSearchParams, + { rejectValue: RejectMessage; state: RootState } +>( + "disbursements/getDisbursementsWithParamsAction", + async (params, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + const { searchParams } = getState().disbursements; + + const newParams = { ...searchParams, ...params }; + + try { + const disbursements = await getDisbursements(token, newParams); + refreshSessionToken(dispatch); + + return { + disbursements: disbursements, + searchParams: newParams, + }; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching paginated disbursements: ${errorString}`, + }); + } + }, +); + +const initialState: DisbursementsInitialState = { + items: [], + status: undefined, + pagination: undefined, + errorString: undefined, + searchParams: undefined, +}; + +const disbursementsSlice = createSlice({ + name: "disbursements", + initialState, + reducers: {}, + extraReducers: (builder) => { + // Get disbursements + builder.addCase(getDisbursementsAction.pending, (state = initialState) => { + state.status = "PENDING"; + }); + builder.addCase(getDisbursementsAction.fulfilled, (state, action) => { + state.items = formatDisbursements(action.payload.data); + state.pagination = action.payload.pagination; + state.status = "SUCCESS"; + state.errorString = undefined; + state.searchParams = undefined; + }); + builder.addCase(getDisbursementsAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + // Disbursements with search params + builder.addCase( + getDisbursementsWithParamsAction.pending, + (state = initialState) => { + state.status = "PENDING"; + }, + ); + builder.addCase( + getDisbursementsWithParamsAction.fulfilled, + (state, action) => { + state.items = formatDisbursements(action.payload.disbursements.data); + state.pagination = action.payload.disbursements.pagination; + state.status = "SUCCESS"; + state.errorString = undefined; + state.searchParams = action.payload.searchParams; + }, + ); + builder.addCase( + getDisbursementsWithParamsAction.rejected, + (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }, + ); + }, +}); + +export const disbursementsSelector = (state: RootState) => state.disbursements; +export const { reducer } = disbursementsSlice; diff --git a/src/store/ducks/forgotPassword.ts b/src/store/ducks/forgotPassword.ts new file mode 100644 index 0000000..d573ea9 --- /dev/null +++ b/src/store/ducks/forgotPassword.ts @@ -0,0 +1,96 @@ +import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { RootState } from "store"; +import { ApiError, ForgotPasswordInitialState, RejectMessage } from "types"; +import { postForgotPassword } from "api/postForgotPassword"; +import { postResetPassword } from "api/postResetPassword"; +import { handleApiErrorString } from "api/handleApiErrorString"; + +export const sendResetPasswordLinkAction = createAsyncThunk< + string, + { email: string; recaptchaToken: string }, + { rejectValue: RejectMessage; state: RootState } +>( + "forgotPassword/sendResetPasswordLinkAction", + async ({ email, recaptchaToken }, { rejectWithValue }) => { + try { + const response = await postForgotPassword(email, recaptchaToken); + return response.message; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + + return rejectWithValue({ + errorString: `Error sending reset password link: ${errorString}`, + }); + } + }, +); + +export const resetPasswordAction = createAsyncThunk< + string, + { password: string; confirmationToken: string }, + { rejectValue: RejectMessage; state: RootState } +>( + "forgotPassword/resetPasswordAction", + async ({ password, confirmationToken }, { rejectWithValue }) => { + try { + await postResetPassword(password, confirmationToken); + return ""; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + + return rejectWithValue({ + errorString: `Error resetting password: ${errorString}`, + }); + } + }, +); + +const initialState: ForgotPasswordInitialState = { + response: undefined, + status: undefined, + errorString: undefined, +}; + +const forgotPasswordSlice = createSlice({ + name: "forgotPassword", + initialState, + reducers: { + resetForgotPasswordAction: () => initialState, + }, + extraReducers: (builder) => { + // Forgot password + builder.addCase( + sendResetPasswordLinkAction.pending, + (state = initialState) => { + state.status = "PENDING"; + }, + ); + builder.addCase(sendResetPasswordLinkAction.fulfilled, (state, action) => { + state.response = action.payload; + state.status = "SUCCESS"; + state.errorString = undefined; + }); + builder.addCase(sendResetPasswordLinkAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + // Reset password + builder.addCase(resetPasswordAction.pending, (state = initialState) => { + state.status = "PENDING"; + }); + builder.addCase(resetPasswordAction.fulfilled, (state, action) => { + state.response = action.payload; + state.status = "SUCCESS"; + state.errorString = undefined; + }); + builder.addCase(resetPasswordAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + }, +}); + +export const forgotPasswordSelector = (state: RootState) => + state.forgotPassword; +export const { reducer } = forgotPasswordSlice; +export const { resetForgotPasswordAction } = forgotPasswordSlice.actions; diff --git a/src/store/ducks/organization.ts b/src/store/ducks/organization.ts new file mode 100644 index 0000000..6384433 --- /dev/null +++ b/src/store/ducks/organization.ts @@ -0,0 +1,215 @@ +import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { RootState } from "store"; +import { handleApiErrorString } from "api/handleApiErrorString"; +import { getOrgInfo } from "api/getOrgInfo"; +import { patchOrgInfo } from "api/patchOrgInfo"; +import { getOrgLogo } from "api/getOrgLogo"; +import { getStellarAccountInfo } from "api/getStellarAccountInfo"; +import { endSessionIfTokenInvalid } from "helpers/endSessionIfTokenInvalid"; +import { refreshSessionToken } from "helpers/refreshSessionToken"; +import { + ApiError, + ApiOrgInfo, + OrgUpdateInfo, + OrganizationInitialState, + RejectMessage, + StellarAccountInfo, +} from "types"; + +export const getOrgInfoAction = createAsyncThunk< + ApiOrgInfo, + undefined, + { rejectValue: RejectMessage; state: RootState } +>( + "organization/getOrgInfoAction", + async (_, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + + try { + const orgInfo = await getOrgInfo(token); + refreshSessionToken(dispatch); + + return orgInfo; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching organization info: ${errorString}`, + }); + } + }, +); + +export const updateOrgInfoAction = createAsyncThunk< + string, + OrgUpdateInfo, + { rejectValue: RejectMessage; state: RootState } +>( + "organization/updateOrgInfoAction", + async ({ name, timezone, logo }, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + + try { + const orgInfo = await patchOrgInfo(token, { name, timezone, logo }); + return orgInfo.message; + } catch (error: unknown) { + const err = error as ApiError; + const errorString = handleApiErrorString(err); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error updating organization info: ${errorString}`, + errorExtras: err?.extras, + }); + } + }, +); + +export const getOrgLogoAction = createAsyncThunk< + string, + undefined, + { rejectValue: RejectMessage; state: RootState } +>( + "organization/getOrgLogoAction", + async (_, { rejectWithValue, dispatch }) => { + try { + return await getOrgLogo(); + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching organization logo: ${errorString}`, + }); + } + }, +); + +export const getStellarAccountAction = createAsyncThunk< + StellarAccountInfo, + string, + { rejectValue: RejectMessage; state: RootState } +>( + "organization/getStellarAccount", + async (stellarAddress, { rejectWithValue }) => { + try { + const accountInfo = await getStellarAccountInfo(stellarAddress); + const balances = accountInfo.balances.map((b) => ({ + balance: b.balance, + assetCode: b.asset_code ?? "XLM", + assetIssuer: b.asset_issuer ?? "native", + })); + + return { address: accountInfo.id, balances }; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + + return rejectWithValue({ + errorString: `Error fetching Stellar account info: ${errorString}`, + }); + } + }, +); + +const initialState: OrganizationInitialState = { + data: { + name: "", + logo: "", + distributionAccountPublicKey: "", + timezoneUtcOffset: "", + assetBalances: undefined, + }, + updateMessage: undefined, + status: undefined, + errorString: undefined, + errorExtras: undefined, +}; + +const organizationSlice = createSlice({ + name: "organization", + initialState, + reducers: { + clearUpdateMessageAction: (state) => { + state.updateMessage = undefined; + }, + clearErrorAction: (state) => { + state.errorString = undefined; + state.errorExtras = undefined; + }, + }, + extraReducers: (builder) => { + // Get org info + builder.addCase(getOrgInfoAction.pending, (state = initialState) => { + state.status = "PENDING"; + state.errorString = undefined; + state.errorExtras = undefined; + }); + builder.addCase(getOrgInfoAction.fulfilled, (state, action) => { + state.data = { + ...state.data, + name: action.payload.name, + distributionAccountPublicKey: + action.payload.distribution_account_public_key, + timezoneUtcOffset: action.payload.timezone_utc_offset, + }; + state.status = "SUCCESS"; + }); + builder.addCase(getOrgInfoAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + state.errorExtras = action.payload?.errorExtras; + }); + // Update org info + builder.addCase(updateOrgInfoAction.pending, (state = initialState) => { + state.updateMessage = undefined; + state.status = "PENDING"; + state.errorString = undefined; + state.errorExtras = undefined; + }); + builder.addCase(updateOrgInfoAction.fulfilled, (state, action) => { + state.updateMessage = action.payload; + state.status = "SUCCESS"; + }); + builder.addCase(updateOrgInfoAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + state.errorExtras = action.payload?.errorExtras; + }); + // Get org logo + builder.addCase(getOrgLogoAction.pending, (state = initialState) => { + state.status = "PENDING"; + }); + builder.addCase(getOrgLogoAction.fulfilled, (state, action) => { + state.data = { + ...state.data, + logo: action.payload, + }; + state.status = "SUCCESS"; + }); + builder.addCase(getOrgLogoAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + // Stellar account + builder.addCase(getStellarAccountAction.pending, (state = initialState) => { + state.status = "PENDING"; + }); + builder.addCase(getStellarAccountAction.fulfilled, (state, action) => { + state.data = { + ...state.data, + assetBalances: [action.payload], + }; + state.status = "SUCCESS"; + }); + builder.addCase(getStellarAccountAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + }, +}); + +export const organizationSelector = (state: RootState) => state.organization; +export const { reducer } = organizationSlice; +export const { clearUpdateMessageAction, clearErrorAction } = + organizationSlice.actions; diff --git a/src/store/ducks/paymentDetails.ts b/src/store/ducks/paymentDetails.ts new file mode 100644 index 0000000..f867c46 --- /dev/null +++ b/src/store/ducks/paymentDetails.ts @@ -0,0 +1,197 @@ +import { PayloadAction, createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { getPaymentDetails } from "api/getPaymentDetails"; +import { getReceiverDetails } from "api/getReceiverDetails"; +import { handleApiErrorString } from "api/handleApiErrorString"; +import { RootState } from "store"; +import { endSessionIfTokenInvalid } from "helpers/endSessionIfTokenInvalid"; +import { refreshSessionToken } from "helpers/refreshSessionToken"; +import { + ApiError, + ApiPayment, + ApiReceiver, + PaymentDetailsInfo, + PaymentDetailsInitialState, + PaymentDetailsReceiver, + PaymentDetailsStatusHistoryItem, + RejectMessage, +} from "types"; + +export const getPaymentDetailsAction = createAsyncThunk< + ApiPayment, + string, + { rejectValue: RejectMessage; state: RootState } +>( + "paymentDetails/getPaymentDetailsAction", + async (paymentId, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + + try { + const payment = await getPaymentDetails(token, paymentId); + refreshSessionToken(dispatch); + + return payment; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching payment details: ${errorString}`, + }); + } + }, +); + +export const getPaymentDetailsReceiverAction = createAsyncThunk< + { receiver: ApiReceiver; receiverWalletId: string | undefined }, + string, + { rejectValue: RejectMessage; state: RootState } +>( + "paymentDetails/getPaymentDetailsReceiverAction", + async (receiverId, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + const { receiverWalletId } = getState().paymentDetails.details; + + try { + const receiver = await getReceiverDetails(token, receiverId); + refreshSessionToken(dispatch); + + return { receiver, receiverWalletId }; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching payment details receiver: ${errorString}`, + }); + } + }, +); + +const initialState: PaymentDetailsInitialState = { + details: { + id: "", + createdAt: "", + disbursementName: "", + disbursementId: "", + receiverId: "", + receiverWalletId: "", + transactionId: "", + senderAddress: "", + totalAmount: "", + assetCode: "", + }, + statusHistory: [], + receiver: undefined, + status: undefined, + errorString: undefined, +}; + +const paymentDetailsSlice = createSlice({ + name: "paymentDetails", + initialState, + reducers: { + setPaymentDetailsAction: (state, action: PayloadAction) => { + state.details = formatPaymentState(action.payload); + state.statusHistory = formatStatusHistory(action.payload); + }, + resetPaymentDetailsAction: () => initialState, + }, + extraReducers: (builder) => { + // Payment details + builder.addCase(getPaymentDetailsAction.pending, (state = initialState) => { + state.status = "PENDING"; + }); + builder.addCase(getPaymentDetailsAction.fulfilled, (state, action) => { + state.details = formatPaymentState(action.payload); + state.statusHistory = formatStatusHistory(action.payload); + state.status = "SUCCESS"; + state.errorString = undefined; + }); + builder.addCase(getPaymentDetailsAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + // Payment receiver + builder.addCase( + getPaymentDetailsReceiverAction.pending, + (state = initialState) => { + state.status = "PENDING"; + }, + ); + builder.addCase( + getPaymentDetailsReceiverAction.fulfilled, + (state, action) => { + state.receiver = formatPaymentReceiver(action.payload); + state.status = "SUCCESS"; + state.errorString = undefined; + }, + ); + builder.addCase( + getPaymentDetailsReceiverAction.rejected, + (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }, + ); + }, +}); + +export const paymentDetailsSelector = (state: RootState) => + state.paymentDetails; +export const { reducer } = paymentDetailsSlice; +export const { setPaymentDetailsAction, resetPaymentDetailsAction } = + paymentDetailsSlice.actions; + +// Helpers +const formatStatusHistory = ( + payment: ApiPayment, +): PaymentDetailsStatusHistoryItem[] => { + return payment.status_history.map((h) => { + return { + updatedAt: h.timestamp, + message: h.status_message, + status: h.status, + }; + }); +}; + +const formatPaymentState = (payload: ApiPayment): PaymentDetailsInfo => { + return { + id: payload.id, + createdAt: payload.created_at, + disbursementName: payload.disbursement.name, + disbursementId: payload.disbursement.id, + receiverId: payload?.receiver_wallet?.receiver?.id, + receiverWalletId: payload?.receiver_wallet?.id, + transactionId: payload.stellar_transaction_id, + senderAddress: payload.stellar_address || "", + totalAmount: payload.amount, + assetCode: payload.asset.code, + }; +}; + +const formatPaymentReceiver = (payload: { + receiver: ApiReceiver; + receiverWalletId: string | undefined; +}): PaymentDetailsReceiver => { + const { receiver, receiverWalletId } = payload; + const paymentWallet = receiverWalletId + ? receiver.wallets.find((w) => w.id === receiverWalletId) + : undefined; + + return { + id: receiver.id, + phoneNumber: receiver.phone_number, + walletAddress: paymentWallet?.stellar_address || "", + provider: paymentWallet?.wallet.name || "", + totalPaymentsCount: Number(receiver.total_payments), + successfulPaymentsCount: Number(receiver.successful_payments), + createdAt: paymentWallet?.created_at || "", + amountsReceived: receiver.received_amounts.map((a) => ({ + amount: a.received_amount, + assetCode: a.asset_code, + assetIssuer: a.asset_issuer, + })), + status: paymentWallet?.status, + }; +}; diff --git a/src/store/ducks/payments.ts b/src/store/ducks/payments.ts new file mode 100644 index 0000000..eb14605 --- /dev/null +++ b/src/store/ducks/payments.ts @@ -0,0 +1,124 @@ +import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { RootState } from "store"; +import { getPayments } from "api/getPayments"; +import { handleApiErrorString } from "api/handleApiErrorString"; +import { endSessionIfTokenInvalid } from "helpers/endSessionIfTokenInvalid"; +import { refreshSessionToken } from "helpers/refreshSessionToken"; +import { + ApiError, + ApiPayments, + PaymentsInitialState, + PaymentsSearchParams, + RejectMessage, +} from "types"; + +export const getPaymentsAction = createAsyncThunk< + ApiPayments, + undefined, + { rejectValue: RejectMessage; state: RootState } +>( + "payments/getPaymentsAction", + async (_, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + + try { + const payments = await getPayments(token); + refreshSessionToken(dispatch); + + return payments; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching payments: ${errorString}`, + }); + } + }, +); + +export const getPaymentsWithParamsAction = createAsyncThunk< + { + payments: ApiPayments; + searchParams: PaymentsSearchParams; + }, + PaymentsSearchParams, + { rejectValue: RejectMessage; state: RootState } +>( + "payments/getPaymentsWithParamsAction", + async (params, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + const { searchParams } = getState().payments; + + const newParams = { ...searchParams, ...params }; + + try { + const payments = await getPayments(token, newParams); + refreshSessionToken(dispatch); + + return { + payments: payments, + searchParams: newParams, + }; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching paginated payments: ${errorString}`, + }); + } + }, +); + +const initialState: PaymentsInitialState = { + items: [], + status: undefined, + pagination: undefined, + errorString: undefined, + searchParams: undefined, +}; + +const paymentsSlice = createSlice({ + name: "payments", + initialState, + reducers: {}, + extraReducers: (builder) => { + // Get payments + builder.addCase(getPaymentsAction.pending, (state = initialState) => { + state.status = "PENDING"; + }); + builder.addCase(getPaymentsAction.fulfilled, (state, action) => { + state.items = action.payload.data; + state.pagination = action.payload.pagination; + state.status = "SUCCESS"; + state.errorString = undefined; + state.searchParams = undefined; + }); + builder.addCase(getPaymentsAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + // Payments with search params + builder.addCase( + getPaymentsWithParamsAction.pending, + (state = initialState) => { + state.status = "PENDING"; + }, + ); + builder.addCase(getPaymentsWithParamsAction.fulfilled, (state, action) => { + state.items = action.payload.payments.data; + state.pagination = action.payload.payments.pagination; + state.status = "SUCCESS"; + state.errorString = undefined; + state.searchParams = action.payload.searchParams; + }); + builder.addCase(getPaymentsWithParamsAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + }, +}); + +export const paymentsSelector = (state: RootState) => state.payments; +export const { reducer } = paymentsSlice; diff --git a/src/store/ducks/profile.ts b/src/store/ducks/profile.ts new file mode 100644 index 0000000..72c7391 --- /dev/null +++ b/src/store/ducks/profile.ts @@ -0,0 +1,141 @@ +import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { RootState } from "store"; +import { handleApiErrorString } from "api/handleApiErrorString"; +import { getProfileInfo } from "api/getProfileInfo"; +import { patchProfileInfo } from "api/patchProfileInfo"; +import { endSessionIfTokenInvalid } from "helpers/endSessionIfTokenInvalid"; +import { refreshSessionToken } from "helpers/refreshSessionToken"; +import { + ApiError, + ApiProfileInfo, + ProfileInitialState, + RejectMessage, +} from "types"; + +export const getProfileInfoAction = createAsyncThunk< + ApiProfileInfo, + undefined, + { rejectValue: RejectMessage; state: RootState } +>( + "profile/getProfileInfoAction", + async (_, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + + try { + const profileInfo = await getProfileInfo(token); + refreshSessionToken(dispatch); + + return profileInfo; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching profile info: ${errorString}`, + }); + } + }, +); + +export const updateProfileInfoAction = createAsyncThunk< + string, + { firstName?: string; lastName?: string; email?: string }, + { rejectValue: RejectMessage; state: RootState } +>( + "profile/updateProfileInfoAction", + async ( + { firstName, lastName, email }, + { rejectWithValue, getState, dispatch }, + ) => { + const { token } = getState().userAccount; + + try { + const profileInfo = await patchProfileInfo(token, { + firstName, + lastName, + email, + }); + return profileInfo.message; + } catch (error: unknown) { + const err = error as ApiError; + const errorString = handleApiErrorString(err); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error updating profile info: ${errorString}`, + errorExtras: err?.extras, + }); + } + }, +); + +const initialState: ProfileInitialState = { + data: { + firstName: "", + lastName: "", + email: "", + role: null, + }, + updateMessage: undefined, + status: undefined, + errorString: undefined, + errorExtras: undefined, +}; + +const profileSlice = createSlice({ + name: "profile", + initialState, + reducers: { + clearUpdateMessageAction: (state) => { + state.updateMessage = undefined; + }, + clearErrorAction: (state) => { + state.errorString = undefined; + state.errorExtras = undefined; + }, + }, + extraReducers: (builder) => { + // Get profile + builder.addCase(getProfileInfoAction.pending, (state = initialState) => { + state.status = "PENDING"; + state.errorString = undefined; + state.errorExtras = undefined; + }); + builder.addCase(getProfileInfoAction.fulfilled, (state, action) => { + state.data = { + ...state.data, + firstName: action.payload.first_name, + lastName: action.payload.last_name, + email: action.payload.email, + role: action.payload.roles?.[0] || null, + }; + state.status = "SUCCESS"; + }); + builder.addCase(getProfileInfoAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + state.errorExtras = action.payload?.errorExtras; + }); + // Update profile + builder.addCase(updateProfileInfoAction.pending, (state = initialState) => { + state.updateMessage = undefined; + state.status = "PENDING"; + state.errorString = undefined; + state.errorExtras = undefined; + }); + builder.addCase(updateProfileInfoAction.fulfilled, (state, action) => { + state.updateMessage = action.payload; + state.status = "SUCCESS"; + }); + builder.addCase(updateProfileInfoAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + state.errorExtras = action.payload?.errorExtras; + }); + }, +}); + +export const profileSelector = (state: RootState) => state.profile; +export const { reducer } = profileSlice; +export const { clearUpdateMessageAction, clearErrorAction } = + profileSlice.actions; diff --git a/src/store/ducks/receiverDetails.ts b/src/store/ducks/receiverDetails.ts new file mode 100644 index 0000000..edc3375 --- /dev/null +++ b/src/store/ducks/receiverDetails.ts @@ -0,0 +1,135 @@ +import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { RootState } from "store"; +import { getReceiverDetails } from "api/getReceiverDetails"; +import { handleApiErrorString } from "api/handleApiErrorString"; +import { endSessionIfTokenInvalid } from "helpers/endSessionIfTokenInvalid"; +import { refreshSessionToken } from "helpers/refreshSessionToken"; +import { + ApiError, + ApiReceiver, + ReceiverDetails, + ReceiverDetailsInitialState, + RejectMessage, +} from "types"; + +export const getReceiverDetailsAction = createAsyncThunk< + ReceiverDetails, + string, + { rejectValue: RejectMessage; state: RootState } +>( + "receiverDetails/getReceiverDetailsAction", + async (receiverId, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + + try { + const receiverDetails = await getReceiverDetails(token, receiverId); + refreshSessionToken(dispatch); + + return formatReceiver(receiverDetails); + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching receiver details: ${errorString}`, + }); + } + }, +); + +const initialState: ReceiverDetailsInitialState = { + id: "", + phoneNumber: "", + email: "", + assetCode: "", + totalReceived: "", + orgId: "", + stats: { + paymentsTotalCount: 0, + paymentsSuccessfulCount: 0, + paymentsFailedCount: 0, + paymentsRemainingCount: 0, + }, + wallets: [ + { + id: "", + stellarAddress: "", + provider: "", + invitedAt: "", + createdAt: "", + smsLastSentAt: "", + totalPaymentsCount: 0, + totalAmountReceived: "", + withdrawnAmount: "", + assetCode: "", + }, + ], + status: undefined, + errorString: undefined, +}; + +const receiverDetailsSlice = createSlice({ + name: "receiverDetails", + initialState, + reducers: { + resetReceiverDetailsAction: () => initialState, + }, + extraReducers: (builder) => { + // Get receiver details + builder.addCase( + getReceiverDetailsAction.pending, + (state = initialState) => { + state.status = "PENDING"; + }, + ); + builder.addCase(getReceiverDetailsAction.fulfilled, (state, action) => { + state.id = action.payload.id; + state.phoneNumber = action.payload.phoneNumber; + state.assetCode = action.payload.assetCode; + state.totalReceived = action.payload.totalReceived; + state.stats = action.payload.stats; + state.wallets = action.payload.wallets; + state.orgId = action.payload.orgId; + state.status = "SUCCESS"; + state.errorString = undefined; + }); + builder.addCase(getReceiverDetailsAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + }, +}); + +export const receiverDetailsSelector = (state: RootState) => + state.receiverDetails; +export const { reducer } = receiverDetailsSlice; +export const { resetReceiverDetailsAction } = receiverDetailsSlice.actions; + +const formatReceiver = (receiver: ApiReceiver): ReceiverDetails => ({ + id: receiver.id, + phoneNumber: receiver.phone_number, + orgId: receiver.external_id, + // TODO: how to handle multiple + assetCode: receiver.received_amounts[0].asset_code, + totalReceived: receiver.received_amounts[0].received_amount, + stats: { + paymentsTotalCount: Number(receiver.total_payments), + paymentsSuccessfulCount: Number(receiver.successful_payments), + paymentsFailedCount: Number(receiver.failed_payments), + paymentsRemainingCount: Number(receiver.remaining_payments), + }, + wallets: receiver.wallets.map((w) => ({ + id: w.id, + stellarAddress: w.stellar_address, + provider: w.wallet.name, + invitedAt: w.invited_at, + createdAt: w.created_at, + smsLastSentAt: w.last_sms_sent, + totalPaymentsCount: Number(w.payments_received), + // TODO: how to handle multiple + assetCode: w.received_amounts[0].asset_code, + totalAmountReceived: w.received_amounts[0].received_amount, + // TODO: withdrawn amount + withdrawnAmount: "", + })), +}); diff --git a/src/store/ducks/receiverPayments.ts b/src/store/ducks/receiverPayments.ts new file mode 100644 index 0000000..49f4de8 --- /dev/null +++ b/src/store/ducks/receiverPayments.ts @@ -0,0 +1,143 @@ +import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { RootState } from "store"; +import { getPayments } from "api/getPayments"; +import { handleApiErrorString } from "api/handleApiErrorString"; +import { endSessionIfTokenInvalid } from "helpers/endSessionIfTokenInvalid"; +import { refreshSessionToken } from "helpers/refreshSessionToken"; +import { + ApiError, + ApiPayments, + PaymentsSearchParams, + ReceiverPaymentsInitialState, + RejectMessage, +} from "types"; + +export const getReceiverPaymentsAction = createAsyncThunk< + ApiPayments, + string, + { rejectValue: RejectMessage; state: RootState } +>( + "receiverPayments/getReceiverPaymentsAction", + async (receiverId, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + + try { + const payments = await getPayments(token, { + receiver_id: receiverId, + }); + refreshSessionToken(dispatch); + + return payments; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching receiver payments: ${errorString}`, + }); + } + }, +); + +export const getReceiverPaymentsWithParamsAction = createAsyncThunk< + { + payments: ApiPayments; + searchParams: PaymentsSearchParams; + }, + { + receiver_id: string; + page?: string; + page_limit?: string; + }, + { rejectValue: RejectMessage; state: RootState } +>( + "receiverPayments/getReceiverPaymentsWithParamsAction", + async (params, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + const { searchParams } = getState().receiverPayments; + + const newParams = { ...searchParams, ...params }; + + try { + const payments = await getPayments(token, newParams); + refreshSessionToken(dispatch); + + return { + payments: payments, + searchParams: newParams, + }; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching paginated receiver payments: ${errorString}`, + }); + } + }, +); + +const initialState: ReceiverPaymentsInitialState = { + items: [], + status: undefined, + pagination: undefined, + errorString: undefined, + searchParams: undefined, +}; + +const receiverPaymentsSlice = createSlice({ + name: "receiverPayments", + initialState, + reducers: { + resetReceiverPaymentsAction: () => initialState, + }, + extraReducers: (builder) => { + // Get payments + builder.addCase( + getReceiverPaymentsAction.pending, + (state = initialState) => { + state.status = "PENDING"; + }, + ); + builder.addCase(getReceiverPaymentsAction.fulfilled, (state, action) => { + state.items = action.payload.data; + state.pagination = action.payload.pagination; + state.status = "SUCCESS"; + state.errorString = undefined; + state.searchParams = undefined; + }); + builder.addCase(getReceiverPaymentsAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + // Payments with search params + builder.addCase( + getReceiverPaymentsWithParamsAction.pending, + (state = initialState) => { + state.status = "PENDING"; + }, + ); + builder.addCase( + getReceiverPaymentsWithParamsAction.fulfilled, + (state, action) => { + state.items = action.payload.payments.data; + state.pagination = action.payload.payments.pagination; + state.status = "SUCCESS"; + state.errorString = undefined; + state.searchParams = action.payload.searchParams; + }, + ); + builder.addCase( + getReceiverPaymentsWithParamsAction.rejected, + (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }, + ); + }, +}); + +export const receiverPaymentsSelector = (state: RootState) => + state.receiverPayments; +export const { reducer } = receiverPaymentsSlice; +export const { resetReceiverPaymentsAction } = receiverPaymentsSlice.actions; diff --git a/src/store/ducks/receivers.ts b/src/store/ducks/receivers.ts new file mode 100644 index 0000000..bfa64bf --- /dev/null +++ b/src/store/ducks/receivers.ts @@ -0,0 +1,125 @@ +import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { RootState } from "store"; +import { getReceivers } from "api/getReceivers"; +import { handleApiErrorString } from "api/handleApiErrorString"; +import { formatReceivers } from "helpers/formatReceivers"; +import { endSessionIfTokenInvalid } from "helpers/endSessionIfTokenInvalid"; +import { refreshSessionToken } from "helpers/refreshSessionToken"; +import { + ApiError, + ApiReceivers, + ReceiversInitialState, + ReceiversSearchParams, + RejectMessage, +} from "types"; + +export const getReceiversAction = createAsyncThunk< + ApiReceivers, + undefined, + { rejectValue: RejectMessage; state: RootState } +>( + "receivers/getReceiversAction", + async (_, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + + try { + const receivers = await getReceivers(token); + refreshSessionToken(dispatch); + + return receivers; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching receivers: ${errorString}`, + }); + } + }, +); + +export const getReceiversWithParamsAction = createAsyncThunk< + { + receivers: ApiReceivers; + searchParams: ReceiversSearchParams; + }, + ReceiversSearchParams, + { rejectValue: RejectMessage; state: RootState } +>( + "receivers/getReceiversWithParamsAction", + async (params, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + const { searchParams } = getState().receivers; + + const newParams = { ...searchParams, ...params }; + + try { + const receivers = await getReceivers(token, newParams); + refreshSessionToken(dispatch); + + return { + receivers: receivers, + searchParams: newParams, + }; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching paginated receivers: ${errorString}`, + }); + } + }, +); + +const initialState: ReceiversInitialState = { + items: [], + status: undefined, + pagination: undefined, + errorString: undefined, + searchParams: undefined, +}; + +const receiversSlice = createSlice({ + name: "receivers", + initialState, + reducers: {}, + extraReducers: (builder) => { + // Get receivers + builder.addCase(getReceiversAction.pending, (state = initialState) => { + state.status = "PENDING"; + }); + builder.addCase(getReceiversAction.fulfilled, (state, action) => { + state.items = formatReceivers(action.payload.data); + state.pagination = action.payload.pagination; + state.status = "SUCCESS"; + state.errorString = undefined; + state.searchParams = undefined; + }); + builder.addCase(getReceiversAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + // Receivers with search params + builder.addCase( + getReceiversWithParamsAction.pending, + (state = initialState) => { + state.status = "PENDING"; + }, + ); + builder.addCase(getReceiversWithParamsAction.fulfilled, (state, action) => { + state.items = formatReceivers(action.payload.receivers.data); + state.pagination = action.payload.receivers.pagination; + state.status = "SUCCESS"; + state.errorString = undefined; + state.searchParams = action.payload.searchParams; + }); + builder.addCase(getReceiversWithParamsAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + }, +}); + +export const receiversSelector = (state: RootState) => state.receivers; +export const { reducer } = receiversSlice; diff --git a/src/store/ducks/singleSignOnUserAccount.ts b/src/store/ducks/singleSignOnUserAccount.ts new file mode 100644 index 0000000..f67f02f --- /dev/null +++ b/src/store/ducks/singleSignOnUserAccount.ts @@ -0,0 +1,29 @@ +import { createAsyncThunk } from "@reduxjs/toolkit"; +import { PartialSingleError, SingleSignOnError } from "types"; +import { signInRedirectCallback } from "helpers/singleSingOn"; +import { RootState } from "store"; +import { OIDC_USERNAME_MAPPING } from "constants/settings"; + +// TODO: need to confirm that this still works +export const singleSignOnAction = createAsyncThunk< + { + token: string | undefined; + email: string | undefined; + }, + void, + { rejectValue: PartialSingleError; state: RootState } +>("userAccount/singleSignOnAction", async (_, { rejectWithValue }) => { + try { + const response = await signInRedirectCallback(); + return { + token: response.id_token, + // TODO: SSO user email instead of username + email: response.profile[OIDC_USERNAME_MAPPING], + }; + } catch (error: unknown) { + const err: SingleSignOnError = error as SingleSignOnError; + return rejectWithValue({ + ...err, + }); + } +}); diff --git a/src/store/ducks/statistics.ts b/src/store/ducks/statistics.ts new file mode 100644 index 0000000..aa32fc3 --- /dev/null +++ b/src/store/ducks/statistics.ts @@ -0,0 +1,85 @@ +import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { getStatistics } from "api/getStatistics"; +import { handleApiErrorString } from "api/handleApiErrorString"; +import { RootState } from "store"; +import { endSessionIfTokenInvalid } from "helpers/endSessionIfTokenInvalid"; +import { refreshSessionToken } from "helpers/refreshSessionToken"; +import { + ApiError, + HomeStatistics, + RejectMessage, + StatisticsInitialState, +} from "types"; + +export const getStatisticsAction = createAsyncThunk< + HomeStatistics, + undefined, + { rejectValue: RejectMessage; state: RootState } +>( + "statistics/getStatisticsAction", + async (_, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + + try { + const statistics = await getStatistics(token); + refreshSessionToken(dispatch); + + return { + paymentsSuccessfulCounts: statistics.payment_counters.success, + paymentsFailedCount: statistics.payment_counters.failed, + paymentsRemainingCount: Number( + statistics.payment_counters.total - + statistics.payment_counters.success - + statistics.payment_counters.failed, + ), + paymentsTotalCount: statistics.payment_counters.total, + walletsTotalCount: statistics.receiver_wallets_counters.total, + individualsTotalCount: statistics.total_receivers, + assets: statistics.payment_amounts_by_asset.map((a) => ({ + assetCode: a.asset_code, + success: a.payment_amounts.success.toString(), + average: a.payment_amounts.average.toString(), + })), + }; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching statistics: ${errorString}`, + }); + } + }, +); + +const initialState: StatisticsInitialState = { + stats: undefined, + status: undefined, + errorString: undefined, +}; + +const statisticsSlice = createSlice({ + name: "statistics", + initialState, + reducers: { + clearStatisticsAction: () => initialState, + }, + extraReducers: (builder) => { + builder.addCase(getStatisticsAction.pending, (state = initialState) => { + state.status = "PENDING"; + }); + builder.addCase(getStatisticsAction.fulfilled, (state, action) => { + state.stats = action.payload; + state.status = "SUCCESS"; + state.errorString = undefined; + }); + builder.addCase(getStatisticsAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + }, +}); + +export const statisticsSelector = (state: RootState) => state.statistics; +export const { reducer } = statisticsSlice; +export const { clearStatisticsAction } = statisticsSlice.actions; diff --git a/src/store/ducks/userAccount.ts b/src/store/ducks/userAccount.ts new file mode 100644 index 0000000..9b5d84e --- /dev/null +++ b/src/store/ducks/userAccount.ts @@ -0,0 +1,222 @@ +import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit"; +import { RootState } from "store"; +import { singleSignOnAction } from "store/ducks/singleSignOnUserAccount"; +import { authLogin } from "api/authLogin"; +import { mfAuth } from "api/mfAuth"; +import { authRefreshToken } from "api/authRefreshToken"; +import { handleApiErrorString } from "api/handleApiErrorString"; +import { endSessionIfTokenInvalid } from "helpers/endSessionIfTokenInvalid"; +import { + ApiError, + JwtUser, + RejectMessage, + UserAccountInitialState, +} from "types"; + +export const signInAction = createAsyncThunk< + { token: string | null; message: string } | string, + { + email: string; + password: string; + recaptchaToken: string; + headers: Record; + }, + { rejectValue: RejectMessage; state: RootState } +>( + "userAccount/signInAction", + async ({ email, password, recaptchaToken, headers }, { rejectWithValue }) => { + try { + const response = await authLogin( + email, + password, + recaptchaToken, + headers, + ); + return response; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + + return rejectWithValue({ + errorString, + }); + } + }, +); + +export const refreshTokenAction = createAsyncThunk< + string, + undefined, + { rejectValue: RejectMessage; state: RootState } +>( + "userAccount/refreshTokenAction", + async (_, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + + try { + const newToken = await authRefreshToken(token); + return newToken; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString, + }); + } + }, +); + +export const mfaAction = createAsyncThunk< + { token: string | null; message: string } | string, + { + mfaCode: string; + rememberMe: boolean; + recaptchaToken: string; + headers: Record; + }, + { rejectValue: RejectMessage; state: RootState } +>( + "userAccount/mfaAction", + async ( + { mfaCode, rememberMe, recaptchaToken, headers }, + { rejectWithValue }, + ) => { + try { + const response = await mfAuth( + mfaCode, + rememberMe, + recaptchaToken, + headers, + ); + return response; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + + return rejectWithValue({ + errorString, + }); + } + }, +); + +const initialState: UserAccountInitialState = { + token: "", + email: "", + role: null, + isAuthenticated: false, + needsMFA: null, + isSessionExpired: false, + isTokenRefresh: false, + status: undefined, + errorString: undefined, + restoredPathname: undefined, +}; + +const userAccountSlice = createSlice({ + name: "userAccount", + initialState, + reducers: { + setUserInfoAction: (state, { payload }: PayloadAction) => { + state.email = payload.email; + state.role = payload.roles?.[0] || null; + state.isAuthenticated = true; + }, + clearUserInfoAction: () => initialState, + restoreUserSession: (state, action) => { + state.token = action.payload; + + // We need this to stay on the current route when page is refreshed + if (location.pathname !== "/") { + state.restoredPathname = location.pathname; + } + }, + sessionExpiredAction: (state) => { + state.isSessionExpired = true; + }, + }, + extraReducers: (builder) => { + // signInAction + builder.addCase(signInAction.pending, (state = initialState) => { + state.status = "PENDING"; + }); + builder.addCase(signInAction.fulfilled, (state, action) => { + if (typeof action.payload != "object") return; + state.isAuthenticated = true; + state.isSessionExpired = false; + state.isTokenRefresh = false; + state.status = "SUCCESS"; + state.token = action.payload.token ?? ""; + state.needsMFA = !action.payload.token; + }); + builder.addCase(signInAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + + // refreshTokenAction + builder.addCase(refreshTokenAction.pending, (state = initialState) => { + state.status = "PENDING"; + }); + builder.addCase(refreshTokenAction.fulfilled, (state, action) => { + state.token = action.payload; + state.isTokenRefresh = true; + state.status = "SUCCESS"; + }); + builder.addCase(refreshTokenAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + + // singleSignOnAction + builder.addCase(singleSignOnAction.pending, (state = initialState) => { + state.status = "PENDING"; + }); + builder.addCase(singleSignOnAction.fulfilled, (state, action) => { + state.token = action.payload?.token as string; + state.email = action.payload?.email as string; + // TODO: SSO: handle role + state.isAuthenticated = true; + state.isSessionExpired = false; + state.isTokenRefresh = false; + state.status = "SUCCESS"; + state.errorString = ""; + }); + builder.addCase(singleSignOnAction.rejected, (state, action) => { + state.token = ""; + state.email = ""; + state.role = null; + state.isAuthenticated = false; + state.isSessionExpired = false; + state.status = "ERROR"; + state.errorString = action.payload?.error_description; + }); + + // mfaAction + builder.addCase(mfaAction.pending, (state = initialState) => { + state.status = "PENDING"; + }); + builder.addCase(mfaAction.fulfilled, (state, action) => { + if (typeof action.payload != "object") return; + state.isAuthenticated = true; + state.isSessionExpired = false; + state.isTokenRefresh = false; + state.status = "SUCCESS"; + state.token = action.payload.token ?? ""; + state.needsMFA = !action.payload.token; + }); + builder.addCase(mfaAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + }, +}); + +export const userAccountSelector = (state: RootState) => state.userAccount; + +export const { reducer } = userAccountSlice; +export const { + setUserInfoAction, + clearUserInfoAction, + restoreUserSession, + sessionExpiredAction, +} = userAccountSlice.actions; diff --git a/src/store/ducks/users.ts b/src/store/ducks/users.ts new file mode 100644 index 0000000..fa54cc4 --- /dev/null +++ b/src/store/ducks/users.ts @@ -0,0 +1,250 @@ +import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { RootState } from "store"; +import { getUsers } from "api/getUsers"; +import { handleApiErrorString } from "api/handleApiErrorString"; +import { patchUserStatus } from "api/patchUserStatus"; +import { patchUserRole } from "api/patchUserRole"; +import { endSessionIfTokenInvalid } from "helpers/endSessionIfTokenInvalid"; +import { refreshSessionToken } from "helpers/refreshSessionToken"; +import { + ApiError, + ApiNewUser, + ApiUser, + NewUser, + RejectMessage, + UserRole, + UsersInitialState, +} from "types"; +import { postUser } from "api/postUser"; + +export const getUsersAction = createAsyncThunk< + ApiUser[], + undefined, + { rejectValue: RejectMessage; state: RootState } +>( + "users/getUsersAction", + async (_, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + + try { + const users = await getUsers(token); + refreshSessionToken(dispatch); + + return users; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching users: ${errorString}`, + }); + } + }, +); + +export const changeUserStatusAction = createAsyncThunk< + { id: string; is_active: boolean }, + { userId: string; isActive: boolean }, + { rejectValue: RejectMessage; state: RootState } +>( + "users/changeUserStatusAction", + async ({ userId, isActive }, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + + try { + await patchUserStatus(token, userId, isActive); + refreshSessionToken(dispatch); + + return { + id: userId, + is_active: isActive, + }; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error changing member's status: ${errorString}`, + }); + } + }, +); + +export const changeUserRoleAction = createAsyncThunk< + { id: string; role: UserRole }, + { userId: string; role: UserRole }, + { rejectValue: RejectMessage; state: RootState } +>( + "users/changeUserRoleAction", + async ({ userId, role }, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + + try { + await patchUserRole(token, userId, role); + refreshSessionToken(dispatch); + + return { + id: userId, + role, + }; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error changing member's role: ${errorString}`, + }); + } + }, +); + +export const createNewUserAction = createAsyncThunk< + ApiNewUser, + NewUser, + { rejectValue: RejectMessage; state: RootState } +>( + "users/createNewUserAction", + async ( + { first_name, last_name, email, role }, + { rejectWithValue, getState, dispatch }, + ) => { + const { token } = getState().userAccount; + + try { + const newUser = await postUser(token, { + first_name, + last_name, + email, + role, + }); + refreshSessionToken(dispatch); + + return newUser; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error changing member's role: ${errorString}`, + }); + } + }, +); + +const initialState: UsersInitialState = { + items: [], + updatedUser: { + id: "", + role: null, + is_active: false, + actionType: undefined, + status: undefined, + errorString: undefined, + }, + newUser: { + id: "", + first_name: "", + last_name: "", + role: null, + email: "", + status: undefined, + errorString: undefined, + }, + status: undefined, + errorString: undefined, +}; + +const usersSlice = createSlice({ + name: "users", + initialState, + reducers: { + resetUpdatedUserAction: (state) => { + state.updatedUser = { + id: "", + role: null, + is_active: false, + actionType: undefined, + status: undefined, + errorString: undefined, + }; + }, + resetNewUserAction: (state) => { + state.newUser = { + id: "", + first_name: "", + last_name: "", + role: null, + email: "", + status: undefined, + errorString: undefined, + }; + }, + }, + extraReducers: (builder) => { + // Get users + builder.addCase(getUsersAction.pending, (state = initialState) => { + state.status = "PENDING"; + }); + builder.addCase(getUsersAction.fulfilled, (state, action) => { + state.items = action.payload; + state.status = "SUCCESS"; + state.errorString = undefined; + }); + builder.addCase(getUsersAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + // Change user's status (active or inactive) + builder.addCase(changeUserStatusAction.pending, (state = initialState) => { + state.updatedUser.status = "PENDING"; + state.updatedUser.errorString = undefined; + }); + builder.addCase(changeUserStatusAction.fulfilled, (state, action) => { + state.updatedUser.id = action.payload.id; + state.updatedUser.is_active = action.payload.is_active; + state.updatedUser.actionType = "status"; + state.updatedUser.status = "SUCCESS"; + }); + builder.addCase(changeUserStatusAction.rejected, (state, action) => { + state.updatedUser.status = "ERROR"; + state.updatedUser.errorString = action.payload?.errorString; + }); + // Change user's role + builder.addCase(changeUserRoleAction.pending, (state = initialState) => { + state.updatedUser.status = "PENDING"; + state.updatedUser.errorString = undefined; + }); + builder.addCase(changeUserRoleAction.fulfilled, (state, action) => { + state.updatedUser.id = action.payload.id; + state.updatedUser.role = action.payload.role; + state.updatedUser.actionType = "role"; + state.updatedUser.status = "SUCCESS"; + }); + builder.addCase(changeUserRoleAction.rejected, (state, action) => { + state.updatedUser.status = "ERROR"; + state.updatedUser.errorString = action.payload?.errorString; + }); + // Create user + builder.addCase(createNewUserAction.pending, (state = initialState) => { + state.newUser.status = "PENDING"; + state.newUser.errorString = undefined; + }); + builder.addCase(createNewUserAction.fulfilled, (state, action) => { + state.newUser.id = action.payload.id; + state.newUser.first_name = action.payload.first_name; + state.newUser.last_name = action.payload.last_name; + state.newUser.email = action.payload.email; + state.newUser.role = action.payload.roles[0]; + state.newUser.status = "SUCCESS"; + }); + builder.addCase(createNewUserAction.rejected, (state, action) => { + state.newUser.status = "ERROR"; + state.newUser.errorString = action.payload?.errorString; + }); + }, +}); + +export const usersSelector = (state: RootState) => state.users; +export const { reducer } = usersSlice; +export const { resetUpdatedUserAction, resetNewUserAction } = + usersSlice.actions; diff --git a/src/store/ducks/wallets.ts b/src/store/ducks/wallets.ts new file mode 100644 index 0000000..dc59481 --- /dev/null +++ b/src/store/ducks/wallets.ts @@ -0,0 +1,58 @@ +import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { RootState } from "store"; +import { getWallets } from "api/getWallets"; +import { handleApiErrorString } from "api/handleApiErrorString"; +import { endSessionIfTokenInvalid } from "helpers/endSessionIfTokenInvalid"; +import { ApiError, ApiWallet, RejectMessage, WalletsInitialState } from "types"; + +export const getWalletsAction = createAsyncThunk< + ApiWallet[], + undefined, + { rejectValue: RejectMessage; state: RootState } +>( + "wallets/getWalletsAction", + async (_, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + + try { + const wallets = await getWallets(token); + return wallets; + } catch (error: unknown) { + const errorString = handleApiErrorString(error as ApiError); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error fetching wallets: ${errorString}`, + }); + } + }, +); + +const initialState: WalletsInitialState = { + items: [], + status: undefined, + errorString: undefined, +}; + +const walletsSlice = createSlice({ + name: "wallets", + initialState, + reducers: {}, + extraReducers: (builder) => { + builder.addCase(getWalletsAction.pending, (state = initialState) => { + state.status = "PENDING"; + }); + builder.addCase(getWalletsAction.fulfilled, (state, action) => { + state.items = action.payload; + state.status = "SUCCESS"; + state.errorString = undefined; + }); + builder.addCase(getWalletsAction.rejected, (state, action) => { + state.status = "ERROR"; + state.errorString = action.payload?.errorString; + }); + }, +}); + +export const walletsSelector = (state: RootState) => state.wallets; +export const { reducer } = walletsSlice; diff --git a/src/store/index.ts b/src/store/index.ts new file mode 100644 index 0000000..d23d775 --- /dev/null +++ b/src/store/index.ts @@ -0,0 +1,85 @@ +import { + configureStore, + isPlain, + createAction, + CombinedState, +} from "@reduxjs/toolkit"; +import { combineReducers, Action } from "redux"; +import BigNumber from "bignumber.js"; + +import { RESET_STORE_ACTION_TYPE } from "constants/settings"; + +import { reducer as assets } from "store/ducks/assets"; +import { reducer as countries } from "store/ducks/countries"; +import { reducer as disbursementDetails } from "store/ducks/disbursementDetails"; +import { reducer as disbursementDrafts } from "store/ducks/disbursementDrafts"; +import { reducer as disbursements } from "store/ducks/disbursements"; +import { reducer as forgotPassword } from "store/ducks/forgotPassword"; +import { reducer as organization } from "store/ducks/organization"; +import { reducer as paymentDetails } from "store/ducks/paymentDetails"; +import { reducer as payments } from "store/ducks/payments"; +import { reducer as profile } from "store/ducks/profile"; +import { reducer as receiverDetails } from "store/ducks/receiverDetails"; +import { reducer as receiverPayments } from "store/ducks/receiverPayments"; +import { reducer as receivers } from "store/ducks/receivers"; +import { reducer as statistics } from "store/ducks/statistics"; +import { reducer as userAccount } from "store/ducks/userAccount"; +import { reducer as users } from "store/ducks/users"; +import { reducer as wallets } from "store/ducks/wallets"; + +export type RootState = ReturnType; +export type AppDispatch = typeof store.dispatch; + +const loggerMiddleware = + (storeVal: any) => (next: any) => (action: Action) => { + console.log("Dispatching: ", action.type); + const dispatchedAction = next(action); + console.log("NEW STATE: ", storeVal.getState()); + return dispatchedAction; + }; + +const isSerializable = (value: any) => + BigNumber.isBigNumber(value) || isPlain(value); + +const reducers = combineReducers({ + assets, + countries, + disbursementDetails, + disbursementDrafts, + disbursements, + forgotPassword, + organization, + paymentDetails, + payments, + profile, + receiverDetails, + receiverPayments, + receivers, + statistics, + userAccount, + users, + wallets, +}); + +export const resetStoreAction = createAction(RESET_STORE_ACTION_TYPE); + +const rootReducer = (state: CombinedState, action: Action) => { + // When resetting state for expired session, we need to make sure we keep + // isSessionExpired flag set + const resetState = state?.userAccount?.isSessionExpired + ? { userAccount: { isSessionExpired: true } } + : undefined; + + const newState = action.type === RESET_STORE_ACTION_TYPE ? resetState : state; + return reducers(newState, action); +}; + +export const store = configureStore({ + reducer: rootReducer, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ + serializableCheck: { + isSerializable, + }, + }).concat(loggerMiddleware), +}); diff --git a/src/styles-utils.scss b/src/styles-utils.scss new file mode 100644 index 0000000..9486e6b --- /dev/null +++ b/src/styles-utils.scss @@ -0,0 +1,12 @@ +@use "sass:math"; + +// Convert px to rem +$base-font-size: 16px; + +@function removePxUnit($value) { + @return math.div($value, $value * 0 + 1); +} + +@function pxToRem($pxValue) { + @return #{math.div(removePxUnit($pxValue), removePxUnit($base-font-size))}rem; +} diff --git a/src/styles.scss b/src/styles.scss new file mode 100644 index 0000000..81a20f8 --- /dev/null +++ b/src/styles.scss @@ -0,0 +1,675 @@ +@use "./styles-utils.scss" as *; + +body { + font-family: var(--font-family-base); + font-size: pxToRem(14px); + overflow-y: hidden; +} + +// Container +.Container { + // Sidebar + &__sidebar { + width: pxToRem(242px); + flex-shrink: 0; + flex-grow: 0; + } + + // Content + &__content { + &__inset { + padding: pxToRem(32px); + } + } +} + +// Layout for Sign in, Forgot password, and alike +.CardLayout { + width: pxToRem(408px); + margin: 0 auto auto; + display: flex; + flex-direction: column; + gap: pxToRem(12px); + + .Heading { + color: var(--color-gray-90); + } + + &__heading { + .Heading { + margin-bottom: pxToRem(8px) !important; + } + } + + .Note { + margin-top: 0; + color: var(--color-gray-80); + + ul { + font-size: inherit; + line-height: inherit; + color: currentColor; + list-style-type: disc; + margin-left: pxToRem(8px); + } + } + + form { + background-color: var(--color-gray-00); + border: 1px solid var(--color-gray-30); + border-radius: pxToRem(8px); + padding: pxToRem(32px); + display: flex; + flex-direction: column; + gap: pxToRem(24px); + + .Link { + align-self: center; + margin-top: pxToRem(-8px); + } + } +} + +// Generic +.Note { + font-size: pxToRem(14px); + line-height: pxToRem(22px); + color: var(--color-gray-60); + margin-top: pxToRem(8px); + + &--small { + font-size: pxToRem(12px); + line-height: pxToRem(20px); + } +} + +.Table-v2__cell--secondary { + color: var(--color-gray-60); +} + +.FiltersWithSearch { + &__search { + width: pxToRem(336px); + } + + &__pageLimit { + width: pxToRem(160px); + } +} + +.Notification__message { + .ErrorExtras { + margin-top: pxToRem(8px); + } +} + +// Stat card +.StatCards { + display: grid; + gap: pxToRem(12px); + margin-bottom: pxToRem(32px); + width: pxToRem(1134px); + + &--home { + grid-template-columns: 1fr 1fr 1fr; + } + + &--disbursementDetails { + grid-template-columns: 1fr 2fr; + } + + &--paymentDetails { + grid-template-columns: 1fr 1fr 1fr; + } + + &__card { + --StatCard-grid-columns: 2; + + &--grid { + display: grid; + grid-template-columns: repeat(var(--StatCard-grid-columns), 1fr); + gap: pxToRem(24px); + } + + &--wideGap { + gap: pxToRem(60px); + } + + &--split { + display: flex; + flex-direction: column; + gap: pxToRem(24px); + justify-content: space-between; + height: 100%; + + & > div:first-child { + flex: 1; + } + } + + &--flexCols { + display: flex; + justify-content: space-between; + gap: pxToRem(16px); + + & > * { + flex: 1; + flex-shrink: 0; + } + + & > div:nth-child(2) { + text-align: right; + } + } + + &__title { + font-size: pxToRem(14px); + line-height: pxToRem(22px); + font-weight: var(--font-weight-medium); + } + + &__unit { + font-size: pxToRem(18px); + line-height: pxToRem(26px); + font-weight: var(--font-weight-regular); + margin-top: pxToRem(8px); + } + + --StatCard-template-rows: 3; + + &__column { + display: grid; + grid-template-rows: repeat(var(--StatCard-template-rows), 1fr); + // Adjusting for even padding all around + margin-top: pxToRem(-8px); + margin-bottom: pxToRem(-8px); + } + + &__item { + font-size: pxToRem(14px); + line-height: pxToRem(22px); + + &--fullWidth { + grid-column: 1 / -1; + } + + &--inline { + display: flex; + align-items: center; + justify-content: space-between; + gap: pxToRem(24px); + padding-top: pxToRem(8px); + padding-bottom: pxToRem(8px); + + &__label { + margin-bottom: 0; + } + + &:not(:last-child) { + border-bottom: 1px solid var(--color-gray-30); + } + } + + &__label { + font-weight: var(--font-weight-medium); + color: var(--color-gray-60); + display: block; + margin-bottom: pxToRem(4px); + } + + &__value { + font-weight: var(--font-weight-regular); + color: var(--color-gray-80); + } + } + + &__assets { + margin-top: pxToRem(8px); + font-size: pxToRem(14px); + line-height: pxToRem(22px); + color: var(--color-gray-90); + + .StatCards__card--flexCols { + &:not(:last-child) { + margin-bottom: pxToRem(8px); + } + } + + .AssetAmount__code { + color: var(--color-gray-60); + } + + .AssetAmount__icon { + order: -1; + width: pxToRem(16px); + height: pxToRem(16px); + } + } + + &__walletCounts { + border-top: 1px solid var(--color-gray-30); + padding-bottom: pxToRem(2px); + padding-top: pxToRem(2px); + + .StatCards__card__item__label { + margin-bottom: 0; + } + + .StatCards__card__item--inline { + border-bottom: none; + padding-bottom: 0; + } + } + } + + .InfoTooltip { + text-align: left; + } +} + +// Search inputs +.Search__filter { + width: pxToRem(336px); +} + +.HomeStatistics { + .Notification { + margin-bottom: pxToRem(32px); + } +} + +// Disbursements +.DisbursementForm { + display: flex; + flex-direction: column; + gap: pxToRem(12px); + margin-top: pxToRem(24px); + + .Notification { + margin-bottom: pxToRem(8px); + } + + .UploadCsv, + .CsvPreview { + margin-top: pxToRem(16px); + } + + &__balances { + margin-top: pxToRem(16px); + display: flex; + flex-direction: column; + gap: pxToRem(8px); + font-size: pxToRem(14px); + line-height: pxToRem(22px); + color: var(--color-gray-80); + } +} + +// Disbursement drafts +.DisbursementDrafts { + margin-top: pxToRem(24px); + + &__icon { + display: inline-block; + width: pxToRem(14px); + height: pxToRem(14px); + + svg { + display: block; + width: 100%; + height: 100%; + fill: var(--color-gray-60); + } + } +} + +.SectionBlock { + margin-bottom: pxToRem(24px); +} + +.DetailsSection { + &:not(:first-child) { + margin-top: pxToRem(32px); + } + + & > h2 { + margin-bottom: pxToRem(24px) !important; + } + + h4 { + color: var(--color-gray-70); + font-size: pxToRem(14px); + line-height: pxToRem(22px); + font-weight: var(--font-weight-medium); + margin-bottom: pxToRem(-12px) !important; + } +} + +// Payment details +.PaymentDetails { + &__wrapper { + display: flex; + flex-direction: column; + gap: pxToRem(24px); + } + + &__info { + display: flex; + flex-direction: column; + gap: pxToRem(4px); + font-size: pxToRem(14px); + line-height: pxToRem(22px); + color: var(--color-gray-80); + } +} + +// Receiver details +.ReceiverDetails__wallets { + & > div:not(:last-child) { + margin-bottom: pxToRem(12px); + } + + &__dropdown { + display: flex; + align-items: center; + gap: pxToRem(16px); + + .Select { + width: auto; + } + + .Select__container select { + padding-right: pxToRem(32px); + } + + .Select__icon { + right: pxToRem(8px); + } + } + + &__subtitle { + font-size: pxToRem(14px); + line-height: pxToRem(22px); + color: var(--color-gray-70); + flex-shrink: 0; + } + + &__noRecentPayments { + background-color: var(--color-gray-10); + border-bottom-left-radius: pxToRem(8px); + border-bottom-right-radius: pxToRem(8px); + color: var(--color-gray-70) !important; + } +} + +// Wallets +.WalletBalances { + display: flex; + flex-direction: column; + gap: pxToRem(8px); + + .Title { + color: var(--color-gray-70); + } + + .AssetAmount { + font-size: pxToRem(14px); + line-height: pxToRem(22px); + font-weight: var(--font-weight-medium); + color: var(--color-gray-80); + + &__icon { + order: -1; + width: pxToRem(16px); + height: pxToRem(16px); + border-radius: pxToRem(16px); + margin-right: pxToRem(4px); + } + } +} + +// Card styles +.CardStack { + display: flex; + flex-direction: column; + gap: pxToRem(12px); + + &__card { + display: flex; + flex-direction: column; + gap: pxToRem(16px); + } + + &__title { + font-size: pxToRem(16px); + line-height: pxToRem(24px); + font-weight: var(--font-weight-medium); + color: var(--color-gray-80); + + display: flex; + align-items: center; + justify-content: space-between; + gap: pxToRem(16px); + } + + &__body { + .Note { + margin-top: 0; + } + } + + &__grid { + display: grid; + gap: pxToRem(24px); + grid-template-columns: 1fr 1fr; + } + + &__buttons { + display: flex; + align-items: center; + justify-content: flex-end; + gap: pxToRem(8px); + } + + &__dropdownMenu { + width: pxToRem(18px); + height: pxToRem(24px); + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + + svg { + display: block; + width: 100%; + height: 100%; + fill: var(--color-gray-90); + } + } + + &__infoItem { + .Label { + margin-bottom: pxToRem(4px); + display: block; + } + + &__value { + font-size: pxToRem(14px); + line-height: pxToRem(22px); + font-weight: var(--font-weight-regular); + color: var(--color-gray-80); + } + } + + &__imageUpload { + grid-column: 1/-1; + + .FileUpload { + margin-top: pxToRem(8px); + display: flex; + gap: pxToRem(12px); + + align-items: center; + justify-content: space-between; + transition: background-color var(--anim-transition-default); + } + + .FileUpload__info { + display: flex; + align-items: center; + gap: pxToRem(12px); + font-size: pxToRem(12px); + line-height: pxToRem(20px); + font-weight: var(--font-weight-regular); + color: var(--color-gray-60); + order: -1; + max-width: 60%; + } + + .FileUpload__message { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + } + } +} + +// Users +.UsersTable { + margin-left: pxToRem(-24px); + margin-right: pxToRem(-24px); + margin-bottom: pxToRem(-24px); + + .FlexCellRight { + display: flex; + justify-content: flex-end; + } + + .Table-v2__wrapper { + overflow-x: hidden; + } +} + +.NewUserForm { + display: grid; + grid-template-columns: 1fr 1fr; + gap: pxToRem(12px); + + .RoleDescription { + grid-column: 1 / -1; + font-size: pxToRem(12px); + line-height: pxToRem(20px); + font-weight: var(--font-weight-medium); + color: var(--color-gray-70); + display: flex; + align-items: flex-start; + gap: pxToRem(8px); + + svg { + display: block; + fill: currentColor; + height: pxToRem(14px); + width: pxToRem(14px); + flex-grow: 0; + flex-shrink: 0; + margin-top: pxToRem(3px); + } + } +} + +// Not found / 404 page +.NotFoundPage { + display: flex; + align-items: center; + flex-direction: column; + padding-top: 5%; + + h1 { + margin-bottom: pxToRem(8px) !important; + } + + p.Paragraph { + color: var(--color-gray-70); + font-size: pxToRem(14px); + line-height: pxToRem(22px); + margin-bottom: pxToRem(32px) !important; + } +} + +.Banner { + &__content { + display: flex; + align-items: center; + justify-content: center; + gap: pxToRem(8px); + } + + &__message { + color: var(--color-gray-90); + } + + .Link { + --Link-color-default: var(--color-red-60); + --Link-color-hover: var(--color-red-70); + --Link-color-disabled: var(--color-red-50); + } +} + +// SDS overrides +.sds-theme-light, +.sds-theme-dark { + background-color: var(--color-gray-10) !important; +} + +#root { + --layout-window-width-min: 1200px; + --layout-window-height-min: auto; + + .Heading { + margin-top: 0; + margin-bottom: 0; + } + + // TODO: fix in SDS + .Card { + width: auto; + height: auto; + } + + // TODO: fix in SDS + .Tooltip { + ul { + font-size: inherit; + line-height: inherit; + color: currentColor; + list-style-type: disc; + margin-left: pxToRem(8px); + } + } + + // TODO: fix in SDS + .Notification__message { + ul { + font-size: pxToRem(14px); + line-height: pxToRem(22px); + color: var(--color-gray-70); + list-style-type: disc; + } + } + + // TODO: add to SDS { + .Input__side-element { + .PasswordMaskButton { + width: pxToRem(22px); + height: pxToRem(22px); + background: none; + border: none; + cursor: pointer; + + svg { + display: block; + fill: var(--color-gray-60); + } + } + } +} diff --git a/src/types/@modules.d.ts b/src/types/@modules.d.ts new file mode 100644 index 0000000..91acdd6 --- /dev/null +++ b/src/types/@modules.d.ts @@ -0,0 +1,11 @@ +declare module "*.svg" { + import React = require("react"); + + export const ReactComponent: React.SFC>; + const src: string; + export default src; +} + +declare module "*.png"; +declare module "*.jpeg"; +declare module "*.jpg"; diff --git a/src/types/index.ts b/src/types/index.ts new file mode 100644 index 0000000..affd091 --- /dev/null +++ b/src/types/index.ts @@ -0,0 +1,937 @@ +/* eslint-disable camelcase */ +import { OidcStandardClaims } from "oidc-client-ts"; + +declare global { + interface Window { + _env_: { + API_URL: string; + STELLAR_EXPERT_URL: string; + USDC_ASSET_ISSUER: string; + HORIZON_URL: string; + RECAPTCHA_SITE_KEY: string; + + USE_SSO: boolean; + OIDC_AUTHORITY: string; + OIDC_CLIENT_ID: string; + OIDC_REDIRECT_URI: string; + OIDC_SCOPE: string; + OIDC_USERNAME_MAPPING: keyof Pick< + OidcStandardClaims, + "name" | "preferred_username" | "nickname" + >; + }; + } +} + +// ============================================================================= +// Store +// ============================================================================= +export type ActionStatus = "PENDING" | "SUCCESS" | "ERROR"; + +export interface RejectMessage { + errorString: string; + errorExtras?: AnyObject; +} + +export interface SingleSignOnError { + error: string; + error_description: string; + error_uri: unknown; + form: unknown; + name: string; + session_state: unknown; + state: unknown; + message: string; + stack: string; +} + +export type PartialSingleError = Partial; + +export type UserAccountInitialState = { + token: string; + email: string; + role: UserRole | null; + isAuthenticated: boolean; + needsMFA: boolean | null; + isSessionExpired: boolean; + isTokenRefresh: boolean; + status: ActionStatus | undefined; + errorString?: string; + restoredPathname?: string; +}; + +export type CountriesInitialState = { + items: ApiCountry[]; + status: ActionStatus | undefined; + errorString?: string; +}; + +export type AssetsInitialState = { + items: ApiAsset[]; + status: ActionStatus | undefined; + errorString?: string; +}; + +export type WalletsInitialState = { + items: ApiWallet[]; + status: ActionStatus | undefined; + errorString?: string; +}; + +export type DisbursementDraftsInitialState = { + items: DisbursementDraft[]; + status: ActionStatus | undefined; + newDraftId?: string; + pagination?: Pagination; + errorString?: string; + errorExtras?: AnyObject; + actionType?: DisbursementDraftAction; +}; + +export type DisbursementsInitialState = { + items: Disbursement[]; + status: ActionStatus | undefined; + pagination?: Pagination; + errorString?: string; + searchParams?: DisbursementsSearchParams; +}; + +export type DisbursementDetailsInitialState = { + details: Disbursement; + instructions: DisbursementInstructions; + status: ActionStatus | undefined; + errorString?: string; +}; + +export type ForgotPasswordInitialState = { + response?: string; + status: ActionStatus | undefined; + errorString?: string; +}; + +export type PaymentsInitialState = { + items: ApiPayment[]; + status: ActionStatus | undefined; + pagination?: Pagination; + errorString?: string; + searchParams?: PaymentsSearchParams; +}; + +export type PaymentDetailsInitialState = { + details: PaymentDetailsInfo; + statusHistory: PaymentDetailsStatusHistoryItem[]; + receiver?: PaymentDetailsReceiver; + status: ActionStatus | undefined; + errorString?: string; +}; + +export type StatisticsInitialState = { + stats: HomeStatistics | undefined; + status: ActionStatus | undefined; + errorString?: string; +}; + +export type ReceiversInitialState = { + items: Receiver[]; + status: ActionStatus | undefined; + pagination?: Pagination; + errorString?: string; + searchParams?: ReceiversSearchParams; +}; + +export type ReceiverDetailsInitialState = { + id: string; + phoneNumber: string; + email?: string; + assetCode: string; + totalReceived: string; + orgId: string; + stats: { + paymentsTotalCount: number; + paymentsSuccessfulCount: number; + paymentsFailedCount: number; + paymentsRemainingCount: number; + }; + wallets: ReceiverWallet[]; + status: ActionStatus | undefined; + errorString?: string; +}; + +export type ReceiverPaymentsInitialState = { + items: ApiPayment[]; + status: ActionStatus | undefined; + pagination?: Pagination; + errorString?: string; + searchParams?: PaymentsSearchParams; +}; + +export type OrganizationInitialState = { + data: { + name: string; + logo: string; + distributionAccountPublicKey: string; + timezoneUtcOffset: string; + assetBalances?: StellarAccountInfo[]; + }; + updateMessage?: string; + status: ActionStatus | undefined; + errorString?: string; + errorExtras?: AnyObject; +}; + +export type ProfileInitialState = { + data: AccountProfile; + updateMessage?: string; + status: ActionStatus | undefined; + errorString?: string; + errorExtras?: AnyObject; +}; + +export type UsersInitialState = { + items: ApiUser[]; + updatedUser: { + id: string; + role: UserRole | null; + is_active: boolean; + actionType: "status" | "role" | undefined; + status: ActionStatus | undefined; + errorString?: string; + }; + newUser: { + id: string; + first_name: string; + last_name: string; + role: UserRole | null; + email: string; + status: ActionStatus | undefined; + errorString?: string; + }; + status: ActionStatus | undefined; + errorString?: string; +}; + +export interface Store { + assets: AssetsInitialState; + countries: CountriesInitialState; + disbursementDetails: DisbursementDetailsInitialState; + disbursementDrafts: DisbursementDraftsInitialState; + disbursements: DisbursementsInitialState; + forgotPassword: ForgotPasswordInitialState; + organization: OrganizationInitialState; + paymentDetails: PaymentDetailsInitialState; + payments: PaymentsInitialState; + profile: ProfileInitialState; + receiverDetails: ReceiverDetailsInitialState; + receiverPayments: ReceiverPaymentsInitialState; + receivers: ReceiversInitialState; + statistics: StatisticsInitialState; + userAccount: UserAccountInitialState; + users: UsersInitialState; + wallets: WalletsInitialState; +} + +export type StoreKey = keyof Store; + +// ============================================================================= +// Generic +// ============================================================================= +export type AnyObject = { + [key: string]: any; +}; + +export type Pagination = { + next?: string; + prev?: string; + pages: number; + total?: number; +}; + +export type CommonFilters = { + status?: string; + created_at_after?: string; + created_at_before?: string; + q?: string; +}; + +export type SortParams = { + sort?: SortByDisbursements | SortByReceivers | SortByPayments; + direction?: SortDirection; +}; + +export type PaginationParams = { + page?: string; + page_limit?: string; +}; + +export type DisbursementStep = "edit" | "preview" | "confirmation"; + +export type SortDirection = "default" | "asc" | "desc"; + +export type SortByDisbursements = "name" | "created_at"; + +export type SortByReceivers = "created_at"; + +export type SortByPayments = "created_at"; + +export type StellarAccountBalance = { + balance: string; + assetCode: string; + assetIssuer: string; +}; + +export type StellarAccountInfo = { + address: string; + balances: StellarAccountBalance[]; +}; + +// ============================================================================= +// User +// ============================================================================= +export type JwtUser = { + id: string; + email: string; + roles: UserRole[] | null; +}; + +export type UserRole = + | "owner" + | "financial_controller" + | "developer" + | "business"; + +export type NewUser = { + first_name: string; + last_name: string; + role: UserRole; + email: string; +}; + +// ============================================================================= +// Disbursement +// ============================================================================= +export type DisbursementStatus = + | "DRAFT" + | "READY" + | "STARTED" + | "PAUSED" + | "COMPLETED"; + +// TODO: add other fields +export type DisbursementVerificationField = "DATE_OF_BIRTH"; + +export type DisbursementDraftAction = "save" | "submit"; + +export interface DisbursementInstructions { + csvName?: string; + csvFile?: File; +} + +export interface DisbursementDraft { + details: Disbursement; + instructions: DisbursementInstructions; +} + +export type Disbursement = { + id: string; + name: string; + createdAt: string; + stats?: DisbursementDetailsStats; + receivers?: { + items: DisbursementReceiver[]; + pagination?: Pagination; + searchParams?: ReceiversSearchParams; + }; + country: { + name: string; + code: string; + }; + asset: { + id: string; + code: string; + }; + wallet: { + id: string; + name: string; + }; + status: DisbursementStatus; + fileName?: string; +}; + +export type DisbursementsSearchParams = CommonFilters & + SortParams & + PaginationParams; + +export interface DisbursementDraftRejectMessage extends RejectMessage { + newDraftId?: string; +} + +export type DisbursementDetailsStats = { + paymentsSuccessfulCount: number; + paymentsFailedCount: number; + paymentsRemainingCount: number; + paymentsTotalCount: number; + totalAmount: string; + disbursedAmount: string; + averagePaymentAmount: string; +}; + +export type DisbursementReceiver = { + id: string; + phoneNumber: string; + provider: string; + assetCode: string; + amount: string; + completedAt?: string; + blockchainId: string; + orgId: string; + paymentStatus: PaymentStatus; +}; + +// ============================================================================= +// Payment +// ============================================================================= +export type PaymentStatus = + | "DRAFT" + | "READY" + | "PENDING" + | "PAUSED" + | "SUCCESS" + | "FAILED"; + +export type PaymentsSearchParams = CommonFilters & + SortParams & + PaginationParams & { receiver_id?: string }; + +export type PaymentDetailsStatusHistoryItem = { + updatedAt: string; + message?: string; + status: PaymentStatus; +}; + +export type PaymentDetailsInfo = { + id: string; + createdAt: string; + disbursementName: string; + disbursementId: string; + receiverId?: string; + receiverWalletId?: string; + transactionId: string; + senderAddress: string; + totalAmount: string; + assetCode: string; +}; + +export type PaymentDetailsReceiver = { + id: string; + phoneNumber: string; + walletAddress: string; + provider: string; + totalPaymentsCount: number; + successfulPaymentsCount: number; + createdAt: string; + amountsReceived: AmountReceived[]; + status: ReceiverStatus | undefined; +}; + +// ============================================================================= +// Receiver +// ============================================================================= +export type ReceiverStatus = "DRAFT" | "READY" | "REGISTERED" | "FLAGGED"; + +export type ReceiversSearchParams = CommonFilters & + SortParams & + PaginationParams; + +export type AmountReceived = { + assetCode: string; + assetIssuer: string; + amount: string; +}; + +export type Receiver = { + id: string; + phoneNumber: string; + walletProvider: string[]; + walletsRegisteredCount: number; + totalPaymentsCount: number; + successfulPaymentsCounts: number; + createdAt: string; + amountsReceived: AmountReceived[]; +}; + +export type ReceiverWallet = { + id: string; + stellarAddress: string; + provider: string; + invitedAt: string; + createdAt: string; + smsLastSentAt: string; + totalPaymentsCount: number; + totalAmountReceived: string; + withdrawnAmount: string; + assetCode: string; +}; + +export type ReceiverWalletBalance = { + assetCode: string; + assetIssuer: string; + balance: string; +}; + +export type PaymentOperationKind = "send" | "receive"; + +export type ReceiverWalletPayment = { + id: string; + createdAt: string; + paymentAddress: string; + amount: string; + assetCode: string; + assetIssuer: string; + operationKind: PaymentOperationKind; + transactionHash: string; + memo: string; +}; + +export type ReceiverDetails = { + id: string; + phoneNumber: string; + email?: string; + assetCode: string; + totalReceived: string; + orgId: string; + stats: { + paymentsTotalCount: number; + paymentsSuccessfulCount: number; + paymentsFailedCount: number; + paymentsRemainingCount: number; + }; + wallets: ReceiverWallet[]; +}; + +// ============================================================================= +// Statistics +// ============================================================================= +export type HomeStatistics = { + paymentsSuccessfulCounts: number; + paymentsFailedCount: number; + paymentsRemainingCount: number; + paymentsTotalCount: number; + walletsTotalCount: number; + individualsTotalCount: number; + assets: { + assetCode: string; + success: string; + average: string; + }[]; +}; + +// ============================================================================= +// Profile +// ============================================================================= +export type AccountProfile = { + firstName: string; + lastName: string; + email: string; + role: UserRole | null; +}; + +// ============================================================================= +// Organization +// ============================================================================= +export type OrgUpdateInfo = { + name?: string; + timezone?: string; + logo?: File; +}; + +// ============================================================================= +// API response +// ============================================================================= +export type ApiError = { + error?: string; + extras?: AnyObject; +}; + +export type ApiCountry = { + code: string; + name: string; + created_at: string; + updated_at: string; +}; + +export type ApiAsset = { + id: string; + code: string; + issuer: string; + created_at: string; + updated_at: string; + deleted_at?: string; +}; + +export type ApiWallet = { + id: string; + name: string; + homepage: string; + deep_link_schema: string; + created_at: string; + updated_at: string; +}; + +export type ApiDisbursements = { + data: ApiDisbursement[]; + pagination: Pagination; +}; + +export type ApiDisbursementUser = { + id: string; + name: string; +}; + +export type ApiDisbursementCountry = { + code: string; + name: string; + language: string; + created_at: string; + updated_at: string; +}; + +export type ApiDisbursementWallet = { + id: string; + name: string; + homepage: string; + deep_link_schema?: string; + created_at?: string; + updated_at?: string; +}; + +export type ApiDisbursementAsset = { + id: string; + code: string; + issuer: string; + created_at?: string; + updated_at?: string; +}; + +export type ApiDisbursementHistory = { + user_id: string | null; + status: DisbursementStatus; + timestamp: string; +}; + +export type ApiDisbursement = { + id: string; + name: string; + country: ApiDisbursementCountry; + wallet: ApiDisbursementWallet; + asset: ApiDisbursementAsset; + status: DisbursementStatus; + verification_field: DisbursementVerificationField; + status_history: ApiDisbursementHistory[]; + created_at: string; + updated_at: string; + total_payments: number; + total_payments_sent: number; + total_payments_failed: number; + total_payments_remaining: number; + amount_disbursed: string; + total_amount: string; + average_amount: string; + file_name?: string; +}; + +export type ApiPaymentStatusHistory = { + status: PaymentStatus; + status_message: string; + timestamp: string; +}; + +export type ApiPaymentDisbursement = { + id: string; + name: string; + status: DisbursementStatus; + created_at: string; + updated_at: string; +}; + +export type ApiPaymentAsset = { + id: string; + code: string; + issuer: string; +}; + +export type ApiPaymentReceiverWallet = { + id: string; + receiver: { + id: string; + }; + wallet: { + id: string; + name: string; + }; + stellar_address?: string; + stellar_memo?: string; + stellar_memo_type?: string; + status: ReceiverStatus; + created_at: string; + updated_at: string; +}; + +export type ApiPayment = { + id: string; + amount: string; + stellar_transaction_id: string; + stellar_operation_id: string; + stellar_address?: string; + status: PaymentStatus; + status_history: ApiPaymentStatusHistory[]; + disbursement: ApiPaymentDisbursement; + asset: ApiPaymentAsset; + receiver_wallet: ApiPaymentReceiverWallet; + created_at: string; + updated_at: string; +}; + +export type ApiPayments = { + data: ApiPayment[]; + pagination: Pagination; +}; + +export type ApiStatisticsAsset = { + asset_code: string; + payment_amounts: { + draft: number; + ready: number; + pending: number; + paused: number; + success: number; + failed: number; + average: number; + total: number; + }; +}; + +export type ApiStatistics = { + payment_counters: { + draft: number; + ready: number; + pending: number; + paused: number; + success: number; + failed: number; + total: number; + }; + receiver_wallets_counters: { + draft: number; + ready: number; + registered: number; + flagged: number; + total: number; + }; + payment_amounts_by_asset: ApiStatisticsAsset[]; + total_disbursements: number; + total_receivers: number; +}; + +export type ApiDisbursementReceiver = { + id: string; + phone_number: string; + external_id: string; + receiver_wallet: { + id: string; + receiver: { + id: string; + }; + wallet: { + id: string; + name: string; + }; + status: ReceiverStatus; + created_at: string; + updated_at: string; + }; + payment: { + id: string; + amount: string; + stellar_transaction_id: string; + stellar_operation_id: string; + status: PaymentStatus; + asset: ApiPaymentAsset; + created_at: string; + updated_at: string; + }; + created_at: string; + updated_at: string; +}; + +export type ApiDisbursementReceivers = { + data: ApiDisbursementReceiver[]; + pagination: Pagination; +}; + +export type ApiReceiverWallet = { + id: string; + receiver: { + id: string; + }; + wallet: ApiDisbursementWallet; + stellar_address: string; + stellar_memo: string; + stellar_memo_type: string; + status: ReceiverStatus; + created_at: string; + updated_at: string; + invited_at: string; + last_sms_sent: string; + total_payments: string | number; + payments_received: string | number; + failed_payments: string | number; + remaining_payments: string | number; + received_amounts: { + asset_code: string; + received_amount: string; + }[]; +}; + +export type ApiReceiver = { + created_at: string; + id: string; + phone_number: string; + email?: string; + external_id: string; + total_payments: string | number; + successful_payments: string | number; + failed_payments: string | number; + remaining_payments: string | number; + received_amounts: { + asset_code: string; + asset_issuer: string; + received_amount: string; + }[]; + registered_wallets: string; + wallets: ApiReceiverWallet[]; +}; + +export type ApiReceivers = { + data: ApiReceiver[]; + pagination: Pagination; +}; + +export type ApiProfileInfo = { + first_name: string; + last_name: string; + email: string; + roles: UserRole[] | null; + organization_name: string; +}; + +export type ApiOrgInfo = { + name: string; + logo_url: string; + distribution_account_public_key: string; + timezone_utc_offset: string; +}; + +export type ApiStellarAccountBalance = { + asset_code?: string; + asset_issuer?: string; + balance: string; +}; + +export type ApiStellarAccount = { + id: string; + balances: ApiStellarAccountBalance[]; +}; + +export type ApiUser = { + id: string; + first_name: string; + last_name: string; + email: string; + roles: UserRole[] | null; + is_active: boolean; +}; + +export type ApiNewUser = { + id: string; + first_name: string; + last_name: string; + roles: UserRole[]; + email: string; +}; + +export type ApiStellarOperationRecord = + | ApiStellarOperationPayment + | ApiStellarOperationPathPaymentStrictReceive + | ApiStellarOperationPathPaymentStrictSend; + +export type ApiStellarPaymentType = + | "payment" + | "path_payment_strict_send" + | "path_payment_strict_receive"; + +export interface ApiStellarOperationBase { + id: number; + paging_token: string; + type_i: number; + type: ApiStellarPaymentType; + transaction_hash: string; + transaction_successful: boolean; + source_account: string; + created_at: string; +} + +export interface ApiStellarOperationPayment extends ApiStellarOperationBase { + asset_type: string; + asset_code: string; + asset_issuer: string; + from: string; + to: string; + amount: string; +} + +export interface ApiStellarOperationPathPayment + extends ApiStellarOperationBase, + ApiStellarOperationPayment { + path: { + asset_type: string; + asset_code: string; + asset_issuer: string; + }[]; + source_amount: string; + source_asset_type: string; + source_asset_code: string; + source_asset_issuer: string; +} + +export interface ApiStellarOperationPathPaymentStrictReceive + extends ApiStellarOperationPathPayment { + source_max: string; +} + +export interface ApiStellarOperationPathPaymentStrictSend + extends ApiStellarOperationPathPayment { + destination_min: string; +} + +export type ApiStellarTransaction = { + id: string; + paging_token: string; + successful: boolean; + hash: string; + ledger: number; + created_at: string; + source_account: string; + source_account_sequence: string; + fee_charged: string; + max_fee: string; + operation_count: number; + envelope_xdr: string; + result_xdr: string; + result_meta_xdr: string; + fee_meta_xdr: string; + memo: string; + memo_type: string; + signatures: string[]; + valid_after: string; + valid_before: string; +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..3d27cc1 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "@stellar/tsconfig", + "compilerOptions": { + "baseUrl": "src/", + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "module": "esnext", + "moduleResolution": "node", + "noEmit": true, + "jsx": "react-jsx", + "allowSyntheticDefaultImports": true + }, + "include": ["src"] +} diff --git a/webpack.common.js b/webpack.common.js new file mode 100644 index 0000000..f793840 --- /dev/null +++ b/webpack.common.js @@ -0,0 +1,157 @@ +const path = require("path"); +const HtmlWebpackPlugin = require("html-webpack-plugin"); +const { CleanWebpackPlugin } = require("clean-webpack-plugin"); +const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); +const MiniCssExtractPlugin = require("mini-css-extract-plugin"); +const CopyPlugin = require("copy-webpack-plugin"); +const ESLintPlugin = require("eslint-webpack-plugin"); +const ProvidePlugin = require("webpack").ProvidePlugin; +const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin"); + +module.exports = { + entry: "./src/index.tsx", + mode: "development", + optimization: { + usedExports: true, + splitChunks: { + cacheGroups: { + source: { + test: /[\\/]src[\\/]/, + name: "source", + chunks: "all", + }, + "vendor-react-redux": { + test: /[\\/]node_modules[\\/](react|react-dom|react-router|react-router-dom|react-redux|redux|redux-thunk|@reduxjs)[\\/]/, + name: "vendor-react-redux", + chunks: "all", + }, + "vendor-stellar": { + test: /[\\/]node_modules[\\/](@stellar|stellar)[\\/]/, + name: "vendor-stellar", + chunks: "all", + }, + "vendor-wallets": { + test: /[\\/]node_modules[\\/](@albedo|@ledgerhq|trezor)[\\/]/, + name: "vendor-wallets", + chunks: "all", + }, + }, + }, + }, + output: { + filename: "static/[name].[contenthash].js", + path: path.resolve(__dirname, "build"), + // This is needed to set correct path when refreshing on sub-pages (where + // path is not root) + publicPath: "/", + }, + module: { + rules: [ + { + test: /\.tsx?$/, + exclude: /node_modules/, + use: { + loader: "ts-loader", + options: { + // Disable type checker, we will use it in ForkTsCheckerWebpackPlugin + transpileOnly: true, + }, + }, + }, + { + test: /\.(js|jsx)$/, + exclude: /node_modules/, + loader: "babel-loader", + }, + { + test: /\.(scss|css)$/, + use: [ + process.env.NODE_ENV !== "production" + ? "style-loader" + : MiniCssExtractPlugin.loader, + { + loader: "css-loader", + }, + { + loader: "sass-loader", + options: { + sourceMap: true, + }, + }, + ], + }, + { + test: /\.(png|jpg|jpeg|gif)$/i, + type: "asset/resource", + }, + { + test: /\.svg$/i, + exclude: /node_modules/, + use: [ + { + loader: "@svgr/webpack", + options: { + svgoConfig: { + plugins: [ + { + name: "removeViewBox", + active: false, + }, + ], + }, + }, + }, + { + loader: "file-loader", + options: { + name: "[name].[ext]", + outputPath: "assets/", + }, + }, + ], + }, + ], + }, + resolve: { + extensions: [".tsx", ".ts", ".js"], + plugins: [ + // This handles aliases and resolves Design System CSS font paths properly + new TsconfigPathsPlugin({ + configFile: path.resolve(__dirname, "./tsconfig.json"), + }), + ], + // Adding node.js modules + fallback: { + crypto: require.resolve("crypto-browserify"), + stream: require.resolve("stream-browserify"), + assert: require.resolve("assert"), + http: require.resolve("stream-http"), + https: require.resolve("https-browserify"), + os: require.resolve("os-browserify"), + url: require.resolve("url"), + buffer: require.resolve("buffer/"), + }, + }, + plugins: [ + // Buffer + new ProvidePlugin({ + Buffer: ["buffer", "Buffer"], + }), + new CopyPlugin({ + patterns: [{ from: "./public", to: "./" }], + }), + new MiniCssExtractPlugin({ + filename: "static/[name].[contenthash].css", + chunkFilename: "[id].css", + }), + new CleanWebpackPlugin(), + new HtmlWebpackPlugin({ + template: "./src/index.html", + }), + new ForkTsCheckerWebpackPlugin(), + new ESLintPlugin({ + extensions: [".tsx", ".ts", ".js"], + exclude: "node_modules", + }), + ], +}; diff --git a/webpack.dev.js b/webpack.dev.js new file mode 100644 index 0000000..6c455c5 --- /dev/null +++ b/webpack.dev.js @@ -0,0 +1,15 @@ +const path = require("path"); +const { merge } = require("webpack-merge"); +const common = require("./webpack.common.js"); + +module.exports = merge(common, { + mode: "development", + devtool: "cheap-module-source-map", + devServer: { + static: path.join(__dirname, "build"), + historyApiFallback: true, + port: 3000, + open: true, + hot: true, + }, +}); diff --git a/webpack.prod.js b/webpack.prod.js new file mode 100644 index 0000000..015ba8e --- /dev/null +++ b/webpack.prod.js @@ -0,0 +1,7 @@ +const { merge } = require("webpack-merge"); +const common = require("./webpack.common.js"); + +module.exports = merge(common, { + mode: "production", + devtool: "source-map", +}); diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..b34739d --- /dev/null +++ b/yarn.lock @@ -0,0 +1,9218 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + +"@adobe/css-tools@^4.0.1": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.2.0.tgz#e1a84fca468f4b337816fcb7f0964beb620ba855" + integrity sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA== + +"@ampproject/remapping@^2.2.0": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.18.6", "@babel/code-frame@^7.21.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.21.4.tgz#d0fa9e4413aca81f2b23b9442797bda1826edb39" + integrity sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g== + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/code-frame@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.5.tgz#234d98e1551960604f1246e6475891a570ad5658" + integrity sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ== + dependencies: + "@babel/highlight" "^7.22.5" + +"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.20.5", "@babel/compat-data@^7.21.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.21.4.tgz#457ffe647c480dff59c2be092fc3acf71195c87f" + integrity sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g== + +"@babel/compat-data@^7.22.5", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.9.tgz#71cdb00a1ce3a329ce4cbec3a44f9fef35669730" + integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ== + +"@babel/core@^7.16.0": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.4.tgz#c6dc73242507b8e2a27fd13a9c1814f9fa34a659" + integrity sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.21.4" + "@babel/generator" "^7.21.4" + "@babel/helper-compilation-targets" "^7.21.4" + "@babel/helper-module-transforms" "^7.21.2" + "@babel/helpers" "^7.21.0" + "@babel/parser" "^7.21.4" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.21.4" + "@babel/types" "^7.21.4" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.2" + semver "^6.3.0" + +"@babel/core@^7.21.3": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.9.tgz#bd96492c68822198f33e8a256061da3cf391f58f" + integrity sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.22.5" + "@babel/generator" "^7.22.9" + "@babel/helper-compilation-targets" "^7.22.9" + "@babel/helper-module-transforms" "^7.22.9" + "@babel/helpers" "^7.22.6" + "@babel/parser" "^7.22.7" + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.8" + "@babel/types" "^7.22.5" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.2" + semver "^6.3.1" + +"@babel/eslint-parser@^7.16.3": + version "7.21.3" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.21.3.tgz#d79e822050f2de65d7f368a076846e7184234af7" + integrity sha512-kfhmPimwo6k4P8zxNs8+T7yR44q1LdpsZdE1NkCsVlfiuTPRfnGgjaF8Qgug9q9Pou17u6wneYF0lDCZJATMFg== + dependencies: + "@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1" + eslint-visitor-keys "^2.1.0" + semver "^6.3.0" + +"@babel/generator@^7.21.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.4.tgz#64a94b7448989f421f919d5239ef553b37bb26bc" + integrity sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA== + dependencies: + "@babel/types" "^7.21.4" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + +"@babel/generator@^7.22.7", "@babel/generator@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.9.tgz#572ecfa7a31002fa1de2a9d91621fd895da8493d" + integrity sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw== + dependencies: + "@babel/types" "^7.22.5" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + +"@babel/helper-annotate-as-pure@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" + integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-annotate-as-pure@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882" + integrity sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.18.6": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz#acd4edfd7a566d1d51ea975dff38fd52906981bb" + integrity sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.18.6" + "@babel/types" "^7.18.9" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.5.tgz#a3f4758efdd0190d8927fcffd261755937c71878" + integrity sha512-m1EP3lVOPptR+2DwD125gziZNcmoNSHGmJROKoy87loWUQyJaVXDgpmruWqDARZSmtYQ+Dl25okU8+qhVzuykw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9", "@babel/helper-compilation-targets@^7.20.7", "@babel/helper-compilation-targets@^7.21.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz#770cd1ce0889097ceacb99418ee6934ef0572656" + integrity sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg== + dependencies: + "@babel/compat-data" "^7.21.4" + "@babel/helper-validator-option" "^7.21.0" + browserslist "^4.21.3" + lru-cache "^5.1.1" + semver "^6.3.0" + +"@babel/helper-compilation-targets@^7.22.5", "@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz#f9d0a7aaaa7cd32a3f31c9316a69f5a9bcacb892" + integrity sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw== + dependencies: + "@babel/compat-data" "^7.22.9" + "@babel/helper-validator-option" "^7.22.5" + browserslist "^4.21.9" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.21.0": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.21.4.tgz#3a017163dc3c2ba7deb9a7950849a9586ea24c18" + integrity sha512-46QrX2CQlaFRF4TkwfTt6nJD7IHq8539cCL7SDpqWSDeJKY1xylKKY5F/33mJhLZ3mFvKv2gGrVS6NkyF6qs+Q== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.21.0" + "@babel/helper-member-expression-to-functions" "^7.21.0" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-replace-supers" "^7.20.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" + "@babel/helper-split-export-declaration" "^7.18.6" + +"@babel/helper-create-class-features-plugin@^7.22.5", "@babel/helper-create-class-features-plugin@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.9.tgz#c36ea240bb3348f942f08b0fbe28d6d979fab236" + integrity sha512-Pwyi89uO4YrGKxL/eNJ8lfEH55DnRloGPOseaA8NFNL6jAUnn+KccaISiFazCj5IolPPDjGSdzQzXVzODVRqUQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-member-expression-to-functions" "^7.22.5" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + semver "^6.3.1" + +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.20.5": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.21.4.tgz#40411a8ab134258ad2cf3a3d987ec6aa0723cee5" + integrity sha512-M00OuhU+0GyZ5iBBN9czjugzWrEq2vDpf/zCYHxxf93ul/Q5rv+a5h+/+0WnI1AebHNVtl5bFV0qsJoH23DbfA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + regexpu-core "^5.3.1" + +"@babel/helper-create-regexp-features-plugin@^7.22.5": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.9.tgz#9d8e61a8d9366fe66198f57c40565663de0825f6" + integrity sha512-+svjVa/tFwsNSG4NEy1h85+HQ5imbT92Q5/bgtS7P0GTQlP8WuFdqsiABmQouhiFGyV66oGxZFpeYHza1rNsKw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + regexpu-core "^5.3.1" + semver "^6.3.1" + +"@babel/helper-define-polyfill-provider@^0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz#8612e55be5d51f0cd1f36b4a5a83924e89884b7a" + integrity sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww== + dependencies: + "@babel/helper-compilation-targets" "^7.17.7" + "@babel/helper-plugin-utils" "^7.16.7" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + semver "^6.1.2" + +"@babel/helper-define-polyfill-provider@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.1.tgz#af1429c4a83ac316a6a8c2cc8ff45cb5d2998d3a" + 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" + +"@babel/helper-environment-visitor@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" + integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== + +"@babel/helper-environment-visitor@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98" + integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q== + +"@babel/helper-explode-assignable-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz#41f8228ef0a6f1a036b8dfdfec7ce94f9a6bc096" + integrity sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-function-name@^7.18.9", "@babel/helper-function-name@^7.19.0", "@babel/helper-function-name@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz#d552829b10ea9f120969304023cd0645fa00b1b4" + integrity sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg== + dependencies: + "@babel/template" "^7.20.7" + "@babel/types" "^7.21.0" + +"@babel/helper-function-name@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be" + integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ== + dependencies: + "@babel/template" "^7.22.5" + "@babel/types" "^7.22.5" + +"@babel/helper-hoist-variables@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-member-expression-to-functions@^7.20.7", "@babel/helper-member-expression-to-functions@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.21.0.tgz#319c6a940431a133897148515877d2f3269c3ba5" + integrity sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q== + dependencies: + "@babel/types" "^7.21.0" + +"@babel/helper-member-expression-to-functions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.5.tgz#0a7c56117cad3372fbf8d2fb4bf8f8d64a1e76b2" + integrity sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-imports@^7.18.6", "@babel/helper-module-imports@^7.21.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz#ac88b2f76093637489e718a90cec6cf8a9b029af" + integrity sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg== + dependencies: + "@babel/types" "^7.21.4" + +"@babel/helper-module-imports@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz#1a8f4c9f4027d23f520bd76b364d44434a72660c" + integrity sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.20.11", "@babel/helper-module-transforms@^7.21.2": + version "7.21.2" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz#160caafa4978ac8c00ac66636cb0fa37b024e2d2" + integrity sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.20.2" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.19.1" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.21.2" + "@babel/types" "^7.21.2" + +"@babel/helper-module-transforms@^7.22.5", "@babel/helper-module-transforms@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz#92dfcb1fbbb2bc62529024f72d942a8c97142129" + integrity sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ== + dependencies: + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.5" + +"@babel/helper-optimise-call-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe" + integrity sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-optimise-call-expression@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz#f21531a9ccbff644fdd156b4077c16ff0c3f609e" + integrity sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz#d1b9000752b18d0877cff85a5c376ce5c3121629" + integrity sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ== + +"@babel/helper-plugin-utils@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" + integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== + +"@babel/helper-remap-async-to-generator@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz#997458a0e3357080e54e1d79ec347f8a8cd28519" + integrity sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-wrap-function" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/helper-remap-async-to-generator@^7.22.5": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.9.tgz#53a25b7484e722d7efb9c350c75c032d4628de82" + integrity sha512-8WWC4oR4Px+tr+Fp0X3RHDVfINGpF3ad1HIbrc8A77epiR6eMMc6jsgozkzT2uDiOOdoS9cLIQ+XD2XvI2WSmQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-wrap-function" "^7.22.9" + +"@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz#243ecd2724d2071532b2c8ad2f0f9f083bcae331" + integrity sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-member-expression-to-functions" "^7.20.7" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.20.7" + "@babel/types" "^7.20.7" + +"@babel/helper-replace-supers@^7.22.5", "@babel/helper-replace-supers@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz#cbdc27d6d8d18cd22c81ae4293765a5d9afd0779" + integrity sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg== + dependencies: + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-member-expression-to-functions" "^7.22.5" + "@babel/helper-optimise-call-expression" "^7.22.5" + +"@babel/helper-simple-access@^7.20.2": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz#0ab452687fe0c2cfb1e2b9e0015de07fc2d62dd9" + integrity sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA== + dependencies: + "@babel/types" "^7.20.2" + +"@babel/helper-simple-access@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" + integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-skip-transparent-expression-wrappers@^7.20.0": + version "7.20.0" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz#fbe4c52f60518cab8140d77101f0e63a8a230684" + integrity sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg== + dependencies: + "@babel/types" "^7.20.0" + +"@babel/helper-skip-transparent-expression-wrappers@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz#007f15240b5751c537c40e77abb4e89eeaaa8847" + integrity sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-string-parser@^7.19.4": + version "7.19.4" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63" + integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== + +"@babel/helper-string-parser@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" + integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== + +"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" + integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== + +"@babel/helper-validator-identifier@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193" + integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ== + +"@babel/helper-validator-option@^7.18.6", "@babel/helper-validator-option@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz#8224c7e13ace4bafdc4004da2cf064ef42673180" + integrity sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ== + +"@babel/helper-validator-option@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz#de52000a15a177413c8234fa3a8af4ee8102d0ac" + integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw== + +"@babel/helper-wrap-function@^7.18.9": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz#75e2d84d499a0ab3b31c33bcfe59d6b8a45f62e3" + integrity sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q== + dependencies: + "@babel/helper-function-name" "^7.19.0" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.20.5" + "@babel/types" "^7.20.5" + +"@babel/helper-wrap-function@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.22.9.tgz#189937248c45b0182c1dcf32f3444ca153944cb9" + integrity sha512-sZ+QzfauuUEfxSEjKFmi3qDSHgLsTPK/pEpoD/qonZKOtTPTLbf59oabPQ4rKekt9lFcj/hTZaOhWwFYrgjk+Q== + dependencies: + "@babel/helper-function-name" "^7.22.5" + "@babel/template" "^7.22.5" + "@babel/types" "^7.22.5" + +"@babel/helpers@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.21.0.tgz#9dd184fb5599862037917cdc9eecb84577dc4e7e" + integrity sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA== + dependencies: + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.21.0" + "@babel/types" "^7.21.0" + +"@babel/helpers@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.6.tgz#8e61d3395a4f0c5a8060f309fb008200969b5ecd" + integrity sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA== + dependencies: + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.6" + "@babel/types" "^7.22.5" + +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/highlight@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.5.tgz#aa6c05c5407a67ebce408162b7ede789b4d22031" + integrity sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw== + dependencies: + "@babel/helper-validator-identifier" "^7.22.5" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.20.7", "@babel/parser@^7.21.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.4.tgz#94003fdfc520bbe2875d4ae557b43ddb6d880f17" + integrity sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw== + +"@babel/parser@^7.22.5", "@babel/parser@^7.22.7": + version "7.22.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.7.tgz#df8cf085ce92ddbdbf668a7f186ce848c9036cae" + integrity sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q== + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2" + integrity sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.5.tgz#87245a21cd69a73b0b81bcda98d443d6df08f05e" + integrity sha512-NP1M5Rf+u2Gw9qfSO4ihjcTGW5zXTi36ITLd4/EoAcEhIZ0yjMqmftDNl3QC19CX7olhrjpyU454g/2W7X0jvQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz#d9c85589258539a22a901033853101a6198d4ef1" + integrity sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" + "@babel/plugin-proposal-optional-chaining" "^7.20.7" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.5.tgz#fef09f9499b1f1c930da8a0c419db42167d792ca" + integrity sha512-31Bb65aZaUwqCbWMnZPduIZxCBngHFlzyN6Dq6KAJjtx+lx6ohKHubc61OomYi7XwVD4Ol0XCVz4h+pYFR048g== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/plugin-transform-optional-chaining" "^7.22.5" + +"@babel/plugin-proposal-async-generator-functions@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz#bfb7276d2d573cb67ba379984a2334e262ba5326" + integrity sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-remap-async-to-generator" "^7.18.9" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-proposal-class-properties@^7.16.0", "@babel/plugin-proposal-class-properties@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" + 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" + +"@babel/plugin-proposal-class-static-block@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.21.0.tgz#77bdd66fb7b605f3a61302d224bdfacf5547977d" + integrity sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.21.0" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-proposal-decorators@^7.16.4": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.21.0.tgz#70e0c89fdcd7465c97593edb8f628ba6e4199d63" + integrity sha512-MfgX49uRrFUTL/HvWtmx3zmpyzMMr4MTj3d527MLlr/4RTT9G/ytFFP7qet2uM2Ve03b+BkpWUpK+lRXnQ+v9w== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.21.0" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-replace-supers" "^7.20.7" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/plugin-syntax-decorators" "^7.21.0" + +"@babel/plugin-proposal-dynamic-import@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz#72bcf8d408799f547d759298c3c27c7e7faa4d94" + integrity sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-proposal-export-namespace-from@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz#5f7313ab348cdb19d590145f9247540e94761203" + integrity sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-proposal-json-strings@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz#7e8788c1811c393aff762817e7dbf1ebd0c05f0b" + integrity sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-proposal-logical-assignment-operators@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz#dfbcaa8f7b4d37b51e8bfb46d94a5aea2bb89d83" + integrity sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.16.0", "@babel/plugin-proposal-nullish-coalescing-operator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz#fdd940a99a740e577d6c753ab6fbb43fdb9467e1" + integrity sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-proposal-numeric-separator@^7.16.0", "@babel/plugin-proposal-numeric-separator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz#899b14fbafe87f053d2c5ff05b36029c62e13c75" + integrity sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-proposal-object-rest-spread@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz#aa662940ef425779c75534a5c41e9d936edc390a" + integrity sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg== + dependencies: + "@babel/compat-data" "^7.20.5" + "@babel/helper-compilation-targets" "^7.20.7" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.20.7" + +"@babel/plugin-proposal-optional-catch-binding@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz#f9400d0e6a3ea93ba9ef70b09e72dd6da638a2cb" + integrity sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-proposal-optional-chaining@^7.16.0", "@babel/plugin-proposal-optional-chaining@^7.20.7", "@babel/plugin-proposal-optional-chaining@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz#886f5c8978deb7d30f678b2e24346b287234d3ea" + 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" + +"@babel/plugin-proposal-private-methods@^7.16.0", "@babel/plugin-proposal-private-methods@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz#5209de7d213457548a98436fa2882f52f4be6bea" + integrity sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": + version "7.21.0-placeholder-for-preset-env.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" + integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== + +"@babel/plugin-proposal-private-property-in-object@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0.tgz#19496bd9883dd83c23c7d7fc45dcd9ad02dfa1dc" + integrity sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw== + 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" + +"@babel/plugin-proposal-unicode-property-regex@^7.18.6", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz#af613d2cd5e643643b65cded64207b15c85cb78e" + integrity sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-decorators@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.21.0.tgz#d2b3f31c3e86fa86e16bb540b7660c55bd7d0e78" + integrity sha512-tIoPpGBR8UuM4++ccWN3gifhVvQu7ZizuR1fklhRJrd5ewgbkUS+0KVFeWWxELtn18NTLoW32XV7zyOgIAiz+w== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-flow@^7.18.6": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.21.4.tgz#3e37fca4f06d93567c1cd9b75156422e90a67107" + integrity sha512-l9xd3N+XG4fZRxEP3vXdK6RW7vN1Uf5dxzRC/09wV86wqZ/YYQooBIGNsiRdfNR3/q2/5pPzV4B54J/9ctX5jw== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-syntax-import-assertions@^7.20.0": + version "7.20.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz#bb50e0d4bea0957235390641209394e87bdb9cc4" + integrity sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ== + dependencies: + "@babel/helper-plugin-utils" "^7.19.0" + +"@babel/plugin-syntax-import-assertions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz#07d252e2aa0bc6125567f742cd58619cb14dce98" + integrity sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-import-attributes@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz#ab840248d834410b829f569f5262b9e517555ecb" + integrity sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-import-meta@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.18.6", "@babel/plugin-syntax-jsx@^7.21.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz#f264ed7bf40ffc9ec239edabc17a50c4f5b6fea2" + integrity sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-syntax-jsx@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz#a6b68e84fb76e759fc3b93e901876ffabbe1d918" + integrity sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.20.0": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz#2751948e9b7c6d771a8efa59340c15d4a2891ff8" + integrity sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-syntax-typescript@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz#aac8d383b062c5072c647a31ef990c1d0af90272" + integrity sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" + integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-arrow-functions@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz#bea332b0e8b2dab3dafe55a163d8227531ab0551" + integrity sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-transform-arrow-functions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz#e5ba566d0c58a5b2ba2a8b795450641950b71958" + integrity sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-async-generator-functions@^7.22.7": + version "7.22.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.7.tgz#053e76c0a903b72b573cb1ab7d6882174d460a1b" + integrity sha512-7HmE7pk/Fmke45TODvxvkxRMV9RazV+ZZzhOL9AG8G29TLrr3jkjwF7uJfxZ30EoXpO+LJkq4oA8NjO2DTnEDg== + dependencies: + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-remap-async-to-generator" "^7.22.5" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-transform-async-to-generator@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz#dfee18623c8cb31deb796aa3ca84dda9cea94354" + integrity sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q== + dependencies: + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-remap-async-to-generator" "^7.18.9" + +"@babel/plugin-transform-async-to-generator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz#c7a85f44e46f8952f6d27fe57c2ed3cc084c3775" + integrity sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ== + dependencies: + "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-remap-async-to-generator" "^7.22.5" + +"@babel/plugin-transform-block-scoped-functions@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz#9187bf4ba302635b9d70d986ad70f038726216a8" + integrity sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-block-scoped-functions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz#27978075bfaeb9fa586d3cb63a3d30c1de580024" + integrity sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-block-scoping@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.21.0.tgz#e737b91037e5186ee16b76e7ae093358a5634f02" + integrity sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-transform-block-scoping@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.5.tgz#8bfc793b3a4b2742c0983fadc1480d843ecea31b" + integrity sha512-EcACl1i5fSQ6bt+YGuU/XGCeZKStLmyVGytWkpyhCLeQVA0eu6Wtiw92V+I1T/hnezUv7j74dA/Ro69gWcU+hg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-class-properties@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.5.tgz#97a56e31ad8c9dc06a0b3710ce7803d5a48cca77" + integrity sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-class-static-block@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.5.tgz#3e40c46f048403472d6f4183116d5e46b1bff5ba" + integrity sha512-SPToJ5eYZLxlnp1UzdARpOGeC2GbHvr9d/UV0EukuVx8atktg194oe+C5BqQ8jRTkgLRVOPYeXRSBg1IlMoVRA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-transform-classes@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.21.0.tgz#f469d0b07a4c5a7dbb21afad9e27e57b47031665" + integrity sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-compilation-targets" "^7.20.7" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.21.0" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-replace-supers" "^7.20.7" + "@babel/helper-split-export-declaration" "^7.18.6" + globals "^11.1.0" + +"@babel/plugin-transform-classes@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.6.tgz#e04d7d804ed5b8501311293d1a0e6d43e94c3363" + integrity sha512-58EgM6nuPNG6Py4Z3zSuu0xWu2VfodiMi72Jt5Kj2FECmaYk1RrTXA45z6KBFsu9tRgwQDwIiY4FXTt+YsSFAQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-compilation-targets" "^7.22.6" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz#704cc2fd155d1c996551db8276d55b9d46e4d0aa" + integrity sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/template" "^7.20.7" + +"@babel/plugin-transform-computed-properties@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz#cd1e994bf9f316bd1c2dafcd02063ec261bb3869" + integrity sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/template" "^7.22.5" + +"@babel/plugin-transform-destructuring@^7.21.3": + version "7.21.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.21.3.tgz#73b46d0fd11cd6ef57dea8a381b1215f4959d401" + integrity sha512-bp6hwMFzuiE4HqYEyoGJ/V2LeIWn+hLVKc4pnj++E5XQptwhtcGmSayM029d/j2X1bPKGTlsyPwAubuU22KhMA== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-transform-destructuring@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.5.tgz#d3aca7438f6c26c78cdd0b0ba920a336001b27cc" + integrity sha512-GfqcFuGW8vnEqTUBM7UtPd5A4q797LTvvwKxXTgRsFjoqaJiEg9deBG6kWeQYkVEL569NpnmpC0Pkr/8BLKGnQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-dotall-regex@^7.18.6", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz#b286b3e7aae6c7b861e45bed0a2fafd6b1a4fef8" + integrity sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-dotall-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz#dbb4f0e45766eb544e193fb00e65a1dd3b2a4165" + integrity sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-duplicate-keys@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz#687f15ee3cdad6d85191eb2a372c4528eaa0ae0e" + integrity sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-duplicate-keys@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz#b6e6428d9416f5f0bba19c70d1e6e7e0b88ab285" + integrity sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-dynamic-import@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.5.tgz#d6908a8916a810468c4edff73b5b75bda6ad393e" + integrity sha512-0MC3ppTB1AMxd8fXjSrbPa7LT9hrImt+/fcj+Pg5YMD7UQyWp/02+JWpdnCymmsXwIx5Z+sYn1bwCn4ZJNvhqQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-transform-exponentiation-operator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz#421c705f4521888c65e91fdd1af951bfefd4dacd" + integrity sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-exponentiation-operator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz#402432ad544a1f9a480da865fda26be653e48f6a" + integrity sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-export-namespace-from@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.5.tgz#57c41cb1d0613d22f548fddd8b288eedb9973a5b" + integrity sha512-X4hhm7FRnPgd4nDA4b/5V280xCx6oL7Oob5+9qVS5C13Zq4bh1qq7LU0GgRU6b5dBWBvhGaXYVB4AcN6+ol6vg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-transform-flow-strip-types@^7.16.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.21.0.tgz#6aeca0adcb81dc627c8986e770bfaa4d9812aff5" + integrity sha512-FlFA2Mj87a6sDkW4gfGrQQqwY/dLlBAyJa2dJEZ+FHXUVHBflO2wyKvg+OOEzXfrKYIa4HWl0mgmbCzt0cMb7w== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-flow" "^7.18.6" + +"@babel/plugin-transform-for-of@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.21.0.tgz#964108c9988de1a60b4be2354a7d7e245f36e86e" + integrity sha512-LlUYlydgDkKpIY7mcBWvyPPmMcOphEyYA27Ef4xpbh1IiDNLr0kZsos2nf92vz3IccvJI25QUwp86Eo5s6HmBQ== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-transform-for-of@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.5.tgz#ab1b8a200a8f990137aff9a084f8de4099ab173f" + integrity sha512-3kxQjX1dU9uudwSshyLeEipvrLjBCVthCgeTp6CzE/9JYrlAIaeekVxRpCWsDDfYTfRZRoCeZatCQvwo+wvK8A== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-function-name@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz#cc354f8234e62968946c61a46d6365440fc764e0" + integrity sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ== + dependencies: + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-function-name@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz#935189af68b01898e0d6d99658db6b164205c143" + integrity sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg== + dependencies: + "@babel/helper-compilation-targets" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-json-strings@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.5.tgz#14b64352fdf7e1f737eed68de1a1468bd2a77ec0" + integrity sha512-DuCRB7fu8MyTLbEQd1ew3R85nx/88yMoqo2uPSjevMj3yoN7CDM8jkgrY0wmVxfJZyJ/B9fE1iq7EQppWQmR5A== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-transform-literals@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz#72796fdbef80e56fba3c6a699d54f0de557444bc" + integrity sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz#e9341f4b5a167952576e23db8d435849b1dd7920" + integrity sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-logical-assignment-operators@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.5.tgz#66ae5f068fd5a9a5dc570df16f56c2a8462a9d6c" + integrity sha512-MQQOUW1KL8X0cDWfbwYP+TbVbZm16QmQXJQ+vndPtH/BoO0lOKpVoEDMI7+PskYxH+IiE0tS8xZye0qr1lGzSA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-transform-member-expression-literals@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz#ac9fdc1a118620ac49b7e7a5d2dc177a1bfee88e" + integrity sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-member-expression-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz#4fcc9050eded981a468347dd374539ed3e058def" + integrity sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-modules-amd@^7.20.11": + version "7.20.11" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz#3daccca8e4cc309f03c3a0c4b41dc4b26f55214a" + integrity sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g== + dependencies: + "@babel/helper-module-transforms" "^7.20.11" + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-transform-modules-amd@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz#4e045f55dcf98afd00f85691a68fc0780704f526" + integrity sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ== + dependencies: + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-modules-commonjs@^7.21.2": + version "7.21.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.21.2.tgz#6ff5070e71e3192ef2b7e39820a06fb78e3058e7" + integrity sha512-Cln+Yy04Gxua7iPdj6nOV96smLGjpElir5YwzF0LBPKoPlLDNJePNlrGGaybAJkd0zKRnOVXOgizSqPYMNYkzA== + dependencies: + "@babel/helper-module-transforms" "^7.21.2" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-simple-access" "^7.20.2" + +"@babel/plugin-transform-modules-commonjs@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.5.tgz#7d9875908d19b8c0536085af7b053fd5bd651bfa" + integrity sha512-B4pzOXj+ONRmuaQTg05b3y/4DuFz3WcCNAXPLb2Q0GT0TrGKGxNKV4jwsXts+StaM0LQczZbOpj8o1DLPDJIiA== + dependencies: + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-simple-access" "^7.22.5" + +"@babel/plugin-transform-modules-systemjs@^7.20.11": + version "7.20.11" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz#467ec6bba6b6a50634eea61c9c232654d8a4696e" + integrity sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw== + dependencies: + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-module-transforms" "^7.20.11" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-validator-identifier" "^7.19.1" + +"@babel/plugin-transform-modules-systemjs@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.5.tgz#18c31410b5e579a0092638f95c896c2a98a5d496" + integrity sha512-emtEpoaTMsOs6Tzz+nbmcePl6AKVtS1yC4YNAeMun9U8YCsgadPNxnOPQ8GhHFB2qdx+LZu9LgoC0Lthuu05DQ== + dependencies: + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.5" + +"@babel/plugin-transform-modules-umd@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz#81d3832d6034b75b54e62821ba58f28ed0aab4b9" + integrity sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ== + dependencies: + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-modules-umd@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz#4694ae40a87b1745e3775b6a7fe96400315d4f98" + integrity sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ== + dependencies: + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz#626298dd62ea51d452c3be58b285d23195ba69a8" + integrity sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.20.5" + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz#67fe18ee8ce02d57c855185e27e3dc959b2e991f" + integrity sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-new-target@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz#d128f376ae200477f37c4ddfcc722a8a1b3246a8" + integrity sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-new-target@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz#1b248acea54ce44ea06dfd37247ba089fcf9758d" + integrity sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-nullish-coalescing-operator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.5.tgz#f8872c65776e0b552e0849d7596cddd416c3e381" + integrity sha512-6CF8g6z1dNYZ/VXok5uYkkBBICHZPiGEl7oDnAx2Mt1hlHVHOSIKWJaXHjQJA5VB43KZnXZDIexMchY4y2PGdA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-transform-numeric-separator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.5.tgz#57226a2ed9e512b9b446517ab6fa2d17abb83f58" + integrity sha512-NbslED1/6M+sXiwwtcAB/nieypGw02Ejf4KtDeMkCEpP6gWFMX1wI9WKYua+4oBneCCEmulOkRpwywypVZzs/g== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-transform-object-rest-spread@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.5.tgz#9686dc3447df4753b0b2a2fae7e8bc33cdc1f2e1" + integrity sha512-Kk3lyDmEslH9DnvCDA1s1kkd3YWQITiBOHngOtDL9Pt6BZjzqb6hiOlb8VfjiiQJ2unmegBqZu0rx5RxJb5vmQ== + dependencies: + "@babel/compat-data" "^7.22.5" + "@babel/helper-compilation-targets" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.22.5" + +"@babel/plugin-transform-object-super@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz#fb3c6ccdd15939b6ff7939944b51971ddc35912c" + integrity sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-replace-supers" "^7.18.6" + +"@babel/plugin-transform-object-super@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz#794a8d2fcb5d0835af722173c1a9d704f44e218c" + integrity sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.5" + +"@babel/plugin-transform-optional-catch-binding@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.5.tgz#842080be3076703be0eaf32ead6ac8174edee333" + integrity sha512-pH8orJahy+hzZje5b8e2QIlBWQvGpelS76C63Z+jhZKsmzfNaPQ+LaW6dcJ9bxTpo1mtXbgHwy765Ro3jftmUg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-transform-optional-chaining@^7.22.5", "@babel/plugin-transform-optional-chaining@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.6.tgz#4bacfe37001fe1901117672875e931d439811564" + integrity sha512-Vd5HiWml0mDVtcLHIoEU5sw6HOUW/Zk0acLs/SAeuLzkGNOPc9DB4nkUajemhCmTIz3eiaKREZn2hQQqF79YTg== + 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" + +"@babel/plugin-transform-parameters@^7.20.7", "@babel/plugin-transform-parameters@^7.21.3": + version "7.21.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.21.3.tgz#18fc4e797cf6d6d972cb8c411dbe8a809fa157db" + integrity sha512-Wxc+TvppQG9xWFYatvCGPvZ6+SIUxQ2ZdiBP+PHYMIjnPXD+uThCshaz4NZOnODAtBjjcVQQ/3OKs9LW28purQ== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-transform-parameters@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.5.tgz#c3542dd3c39b42c8069936e48717a8d179d63a18" + integrity sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-private-methods@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.5.tgz#21c8af791f76674420a147ae62e9935d790f8722" + integrity sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-private-property-in-object@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.5.tgz#07a77f28cbb251546a43d175a1dda4cf3ef83e32" + integrity sha512-/9xnaTTJcVoBtSSmrVyhtSvO3kbqS2ODoh2juEU72c3aYonNF0OMGiaz2gjukyKM2wBBYJP38S4JiE0Wfb5VMQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-transform-property-literals@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz#e22498903a483448e94e032e9bbb9c5ccbfc93a3" + integrity sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-property-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz#b5ddabd73a4f7f26cd0e20f5db48290b88732766" + integrity sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-react-constant-elements@^7.21.3": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.22.5.tgz#6dfa7c1c37f7d7279e417ceddf5a04abb8bb9c29" + integrity sha512-BF5SXoO+nX3h5OhlN78XbbDrBOffv+AxPP2ENaJOVqjWCgBDeOY3WcaUcddutGSfoap+5NEQ/q/4I3WZIvgkXA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-react-display-name@^7.16.0", "@babel/plugin-transform-react-display-name@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz#8b1125f919ef36ebdfff061d664e266c666b9415" + integrity sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-react-jsx-development@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz#dbe5c972811e49c7405b630e4d0d2e1380c0ddc5" + integrity sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA== + dependencies: + "@babel/plugin-transform-react-jsx" "^7.18.6" + +"@babel/plugin-transform-react-jsx@^7.18.6": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.21.0.tgz#656b42c2fdea0a6d8762075d58ef9d4e3c4ab8a2" + integrity sha512-6OAWljMvQrZjR2DaNhVfRz6dkCAVV+ymcLUmaf8bccGOHn2v5rHJK3tTpij0BuhdYWP4LLaqj5lwcdlpAAPuvg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-jsx" "^7.18.6" + "@babel/types" "^7.21.0" + +"@babel/plugin-transform-react-pure-annotations@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz#561af267f19f3e5d59291f9950fd7b9663d0d844" + integrity sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-regenerator@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz#57cda588c7ffb7f4f8483cc83bdcea02a907f04d" + integrity sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + regenerator-transform "^0.15.1" + +"@babel/plugin-transform-regenerator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.5.tgz#cd8a68b228a5f75fa01420e8cc2fc400f0fc32aa" + integrity sha512-rR7KePOE7gfEtNTh9Qw+iO3Q/e4DEsoQ+hdvM6QUDH7JRJ5qxq5AA52ZzBWbI5i9lfNuvySgOGP8ZN7LAmaiPw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + regenerator-transform "^0.15.1" + +"@babel/plugin-transform-reserved-words@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz#b1abd8ebf8edaa5f7fe6bbb8d2133d23b6a6f76a" + integrity sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-reserved-words@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz#832cd35b81c287c4bcd09ce03e22199641f964fb" + integrity sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-runtime@^7.16.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.21.4.tgz#2e1da21ca597a7d01fc96b699b21d8d2023191aa" + integrity sha512-1J4dhrw1h1PqnNNpzwxQ2UBymJUF8KuPjAAnlLwZcGhHAIqUigFW7cdK6GHoB64ubY4qXQNYknoUeks4Wz7CUA== + dependencies: + "@babel/helper-module-imports" "^7.21.4" + "@babel/helper-plugin-utils" "^7.20.2" + babel-plugin-polyfill-corejs2 "^0.3.3" + babel-plugin-polyfill-corejs3 "^0.6.0" + babel-plugin-polyfill-regenerator "^0.4.1" + semver "^6.3.0" + +"@babel/plugin-transform-shorthand-properties@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz#6d6df7983d67b195289be24909e3f12a8f664dc9" + integrity sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-shorthand-properties@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz#6e277654be82b5559fc4b9f58088507c24f0c624" + integrity sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-spread@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz#c2d83e0b99d3bf83e07b11995ee24bf7ca09401e" + integrity sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" + +"@babel/plugin-transform-spread@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz#6487fd29f229c95e284ba6c98d65eafb893fea6b" + integrity sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + +"@babel/plugin-transform-sticky-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz#c6706eb2b1524028e317720339583ad0f444adcc" + integrity sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-sticky-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz#295aba1595bfc8197abd02eae5fc288c0deb26aa" + integrity sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-template-literals@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz#04ec6f10acdaa81846689d63fae117dd9c243a5e" + integrity sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-template-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz#8f38cf291e5f7a8e60e9f733193f0bcc10909bff" + integrity sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-typeof-symbol@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz#c8cea68263e45addcd6afc9091429f80925762c0" + integrity sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-typeof-symbol@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz#5e2ba478da4b603af8673ff7c54f75a97b716b34" + integrity sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-typescript@^7.21.3": + version "7.21.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.21.3.tgz#316c5be579856ea890a57ebc5116c5d064658f2b" + integrity sha512-RQxPz6Iqt8T0uw/WsJNReuBpWpBqs/n7mNo18sKLoTbMp+UrEekhH+pKSVC7gWz+DNjo9gryfV8YzCiT45RgMw== + 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-typescript" "^7.20.0" + +"@babel/plugin-transform-typescript@^7.22.5": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.22.9.tgz#91e08ad1eb1028ecc62662a842e93ecfbf3c7234" + integrity sha512-BnVR1CpKiuD0iobHPaM1iLvcwPYN2uVFAqoLVSpEDKWuOikoCv5HbKLxclhKYUXlWkX86DoZGtqI4XhbOsyrMg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-create-class-features-plugin" "^7.22.9" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-typescript" "^7.22.5" + +"@babel/plugin-transform-unicode-escapes@^7.18.10": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz#1ecfb0eda83d09bbcb77c09970c2dd55832aa246" + integrity sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-unicode-escapes@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.5.tgz#ce0c248522b1cb22c7c992d88301a5ead70e806c" + integrity sha512-biEmVg1IYB/raUO5wT1tgfacCef15Fbzhkx493D3urBI++6hpJ+RFG4SrWMn0NEZLfvilqKf3QDrRVZHo08FYg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-unicode-property-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz#098898f74d5c1e86660dc112057b2d11227f1c81" + integrity sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-unicode-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz#194317225d8c201bbae103364ffe9e2cea36cdca" + integrity sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-unicode-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz#ce7e7bb3ef208c4ff67e02a22816656256d7a183" + integrity sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-unicode-sets-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz#77788060e511b708ffc7d42fdfbc5b37c3004e91" + integrity sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/preset-env@^7.16.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.21.4.tgz#a952482e634a8dd8271a3fe5459a16eb10739c58" + integrity sha512-2W57zHs2yDLm6GD5ZpvNn71lZ0B/iypSdIeq25OurDKji6AdzV07qp4s3n1/x5BqtiGaTrPN3nerlSCaC5qNTw== + dependencies: + "@babel/compat-data" "^7.21.4" + "@babel/helper-compilation-targets" "^7.21.4" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-validator-option" "^7.21.0" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.20.7" + "@babel/plugin-proposal-async-generator-functions" "^7.20.7" + "@babel/plugin-proposal-class-properties" "^7.18.6" + "@babel/plugin-proposal-class-static-block" "^7.21.0" + "@babel/plugin-proposal-dynamic-import" "^7.18.6" + "@babel/plugin-proposal-export-namespace-from" "^7.18.9" + "@babel/plugin-proposal-json-strings" "^7.18.6" + "@babel/plugin-proposal-logical-assignment-operators" "^7.20.7" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.6" + "@babel/plugin-proposal-numeric-separator" "^7.18.6" + "@babel/plugin-proposal-object-rest-spread" "^7.20.7" + "@babel/plugin-proposal-optional-catch-binding" "^7.18.6" + "@babel/plugin-proposal-optional-chaining" "^7.21.0" + "@babel/plugin-proposal-private-methods" "^7.18.6" + "@babel/plugin-proposal-private-property-in-object" "^7.21.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.18.6" + "@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.20.0" + "@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-transform-arrow-functions" "^7.20.7" + "@babel/plugin-transform-async-to-generator" "^7.20.7" + "@babel/plugin-transform-block-scoped-functions" "^7.18.6" + "@babel/plugin-transform-block-scoping" "^7.21.0" + "@babel/plugin-transform-classes" "^7.21.0" + "@babel/plugin-transform-computed-properties" "^7.20.7" + "@babel/plugin-transform-destructuring" "^7.21.3" + "@babel/plugin-transform-dotall-regex" "^7.18.6" + "@babel/plugin-transform-duplicate-keys" "^7.18.9" + "@babel/plugin-transform-exponentiation-operator" "^7.18.6" + "@babel/plugin-transform-for-of" "^7.21.0" + "@babel/plugin-transform-function-name" "^7.18.9" + "@babel/plugin-transform-literals" "^7.18.9" + "@babel/plugin-transform-member-expression-literals" "^7.18.6" + "@babel/plugin-transform-modules-amd" "^7.20.11" + "@babel/plugin-transform-modules-commonjs" "^7.21.2" + "@babel/plugin-transform-modules-systemjs" "^7.20.11" + "@babel/plugin-transform-modules-umd" "^7.18.6" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.20.5" + "@babel/plugin-transform-new-target" "^7.18.6" + "@babel/plugin-transform-object-super" "^7.18.6" + "@babel/plugin-transform-parameters" "^7.21.3" + "@babel/plugin-transform-property-literals" "^7.18.6" + "@babel/plugin-transform-regenerator" "^7.20.5" + "@babel/plugin-transform-reserved-words" "^7.18.6" + "@babel/plugin-transform-shorthand-properties" "^7.18.6" + "@babel/plugin-transform-spread" "^7.20.7" + "@babel/plugin-transform-sticky-regex" "^7.18.6" + "@babel/plugin-transform-template-literals" "^7.18.9" + "@babel/plugin-transform-typeof-symbol" "^7.18.9" + "@babel/plugin-transform-unicode-escapes" "^7.18.10" + "@babel/plugin-transform-unicode-regex" "^7.18.6" + "@babel/preset-modules" "^0.1.5" + "@babel/types" "^7.21.4" + babel-plugin-polyfill-corejs2 "^0.3.3" + babel-plugin-polyfill-corejs3 "^0.6.0" + babel-plugin-polyfill-regenerator "^0.4.1" + core-js-compat "^3.25.1" + semver "^6.3.0" + +"@babel/preset-env@^7.20.2": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.22.9.tgz#57f17108eb5dfd4c5c25a44c1977eba1df310ac7" + integrity sha512-wNi5H/Emkhll/bqPjsjQorSykrlfY5OWakd6AulLvMEytpKasMVUpVy8RL4qBIBs5Ac6/5i0/Rv0b/Fg6Eag/g== + dependencies: + "@babel/compat-data" "^7.22.9" + "@babel/helper-compilation-targets" "^7.22.9" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-validator-option" "^7.22.5" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.22.5" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.22.5" + "@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.22.5" + "@babel/plugin-syntax-import-attributes" "^7.22.5" + "@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.22.5" + "@babel/plugin-transform-async-generator-functions" "^7.22.7" + "@babel/plugin-transform-async-to-generator" "^7.22.5" + "@babel/plugin-transform-block-scoped-functions" "^7.22.5" + "@babel/plugin-transform-block-scoping" "^7.22.5" + "@babel/plugin-transform-class-properties" "^7.22.5" + "@babel/plugin-transform-class-static-block" "^7.22.5" + "@babel/plugin-transform-classes" "^7.22.6" + "@babel/plugin-transform-computed-properties" "^7.22.5" + "@babel/plugin-transform-destructuring" "^7.22.5" + "@babel/plugin-transform-dotall-regex" "^7.22.5" + "@babel/plugin-transform-duplicate-keys" "^7.22.5" + "@babel/plugin-transform-dynamic-import" "^7.22.5" + "@babel/plugin-transform-exponentiation-operator" "^7.22.5" + "@babel/plugin-transform-export-namespace-from" "^7.22.5" + "@babel/plugin-transform-for-of" "^7.22.5" + "@babel/plugin-transform-function-name" "^7.22.5" + "@babel/plugin-transform-json-strings" "^7.22.5" + "@babel/plugin-transform-literals" "^7.22.5" + "@babel/plugin-transform-logical-assignment-operators" "^7.22.5" + "@babel/plugin-transform-member-expression-literals" "^7.22.5" + "@babel/plugin-transform-modules-amd" "^7.22.5" + "@babel/plugin-transform-modules-commonjs" "^7.22.5" + "@babel/plugin-transform-modules-systemjs" "^7.22.5" + "@babel/plugin-transform-modules-umd" "^7.22.5" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.22.5" + "@babel/plugin-transform-new-target" "^7.22.5" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.22.5" + "@babel/plugin-transform-numeric-separator" "^7.22.5" + "@babel/plugin-transform-object-rest-spread" "^7.22.5" + "@babel/plugin-transform-object-super" "^7.22.5" + "@babel/plugin-transform-optional-catch-binding" "^7.22.5" + "@babel/plugin-transform-optional-chaining" "^7.22.6" + "@babel/plugin-transform-parameters" "^7.22.5" + "@babel/plugin-transform-private-methods" "^7.22.5" + "@babel/plugin-transform-private-property-in-object" "^7.22.5" + "@babel/plugin-transform-property-literals" "^7.22.5" + "@babel/plugin-transform-regenerator" "^7.22.5" + "@babel/plugin-transform-reserved-words" "^7.22.5" + "@babel/plugin-transform-shorthand-properties" "^7.22.5" + "@babel/plugin-transform-spread" "^7.22.5" + "@babel/plugin-transform-sticky-regex" "^7.22.5" + "@babel/plugin-transform-template-literals" "^7.22.5" + "@babel/plugin-transform-typeof-symbol" "^7.22.5" + "@babel/plugin-transform-unicode-escapes" "^7.22.5" + "@babel/plugin-transform-unicode-property-regex" "^7.22.5" + "@babel/plugin-transform-unicode-regex" "^7.22.5" + "@babel/plugin-transform-unicode-sets-regex" "^7.22.5" + "@babel/preset-modules" "^0.1.5" + "@babel/types" "^7.22.5" + babel-plugin-polyfill-corejs2 "^0.4.4" + babel-plugin-polyfill-corejs3 "^0.8.2" + babel-plugin-polyfill-regenerator "^0.5.1" + core-js-compat "^3.31.0" + semver "^6.3.1" + +"@babel/preset-modules@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" + integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/preset-react@^7.16.0", "@babel/preset-react@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.18.6.tgz#979f76d6277048dc19094c217b507f3ad517dd2d" + integrity sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-validator-option" "^7.18.6" + "@babel/plugin-transform-react-display-name" "^7.18.6" + "@babel/plugin-transform-react-jsx" "^7.18.6" + "@babel/plugin-transform-react-jsx-development" "^7.18.6" + "@babel/plugin-transform-react-pure-annotations" "^7.18.6" + +"@babel/preset-typescript@^7.16.0": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.21.4.tgz#b913ac8e6aa8932e47c21b01b4368d8aa239a529" + integrity sha512-sMLNWY37TCdRH/bJ6ZeeOH1nPuanED7Ai9Y/vH31IPqalioJ6ZNFUWONsakhv4r4n+I6gm5lmoE0olkgib/j/A== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-validator-option" "^7.21.0" + "@babel/plugin-syntax-jsx" "^7.21.4" + "@babel/plugin-transform-modules-commonjs" "^7.21.2" + "@babel/plugin-transform-typescript" "^7.21.3" + +"@babel/preset-typescript@^7.21.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.22.5.tgz#16367d8b01d640e9a507577ed4ee54e0101e51c8" + integrity sha512-YbPaal9LxztSGhmndR46FmAbkJ/1fAsw293tSU+I5E5h+cnJ3d4GTwyUgGYmOXJYdGA+uNePle4qbaRzj2NISQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-validator-option" "^7.22.5" + "@babel/plugin-syntax-jsx" "^7.22.5" + "@babel/plugin-transform-modules-commonjs" "^7.22.5" + "@babel/plugin-transform-typescript" "^7.22.5" + +"@babel/regjsgen@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" + integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== + +"@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673" + integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw== + dependencies: + regenerator-runtime "^0.13.11" + +"@babel/runtime@^7.21.0": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.6.tgz#57d64b9ae3cff1d67eb067ae117dac087f5bd438" + integrity sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ== + dependencies: + regenerator-runtime "^0.13.11" + +"@babel/template@^7.18.10", "@babel/template@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8" + integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + +"@babel/template@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec" + integrity sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw== + dependencies: + "@babel/code-frame" "^7.22.5" + "@babel/parser" "^7.22.5" + "@babel/types" "^7.22.5" + +"@babel/traverse@^7.20.5", "@babel/traverse@^7.20.7", "@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.21.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.4.tgz#a836aca7b116634e97a6ed99976236b3282c9d36" + integrity sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q== + dependencies: + "@babel/code-frame" "^7.21.4" + "@babel/generator" "^7.21.4" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.21.0" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.21.4" + "@babel/types" "^7.21.4" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/traverse@^7.22.6", "@babel/traverse@^7.22.8": + version "7.22.8" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.8.tgz#4d4451d31bc34efeae01eac222b514a77aa4000e" + integrity sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw== + dependencies: + "@babel/code-frame" "^7.22.5" + "@babel/generator" "^7.22.7" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.22.7" + "@babel/types" "^7.22.5" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.2", "@babel/types@^7.21.4", "@babel/types@^7.4.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.4.tgz#2d5d6bb7908699b3b416409ffd3b5daa25b030d4" + integrity sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA== + dependencies: + "@babel/helper-string-parser" "^7.19.4" + "@babel/helper-validator-identifier" "^7.19.1" + to-fast-properties "^2.0.0" + +"@babel/types@^7.21.3", "@babel/types@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.5.tgz#cd93eeaab025880a3a47ec881f4b096a5b786fbe" + integrity sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA== + dependencies: + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.5" + to-fast-properties "^2.0.0" + +"@discoveryjs/json-ext@^0.5.0": + version "0.5.7" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" + integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.4.0": + version "4.5.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.0.tgz#f6f729b02feee2c749f57e334b7a1b5f40a81724" + integrity sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ== + +"@eslint-community/regexpp@^4.5.1": + version "4.5.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.1.tgz#cdd35dce4fa1a89a4fd42b1599eb35b3af408884" + integrity sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ== + +"@eslint/eslintrc@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.0.tgz#82256f164cc9e0b59669efc19d57f8092706841d" + 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" + +"@eslint/js@8.44.0": + version "8.44.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.44.0.tgz#961a5903c74139390478bdc808bcde3fc45ab7af" + integrity sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw== + +"@floating-ui/core@^1.2.6": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.2.6.tgz#d21ace437cc919cdd8f1640302fa8851e65e75c0" + integrity sha512-EvYTiXet5XqweYGClEmpu3BoxmsQ4hkj3QaYA6qEnigCWffTP3vNRwBReTdrwDwo7OoJ3wM8Uoe9Uk4n+d4hfg== + +"@floating-ui/dom@^1.2.5": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.2.6.tgz#bcf0c7bada97c20d9d1255b889f35bac838c63fe" + integrity sha512-02vxFDuvuVPs22iJICacezYJyf7zwwOCWkPNkWNBr1U0Qt1cKFYzWvxts0AmqcOQGwt/3KJWcWIgtbUU38keyw== + dependencies: + "@floating-ui/core" "^1.2.6" + +"@gar/promisify@^1.0.1", "@gar/promisify@^1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" + integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== + +"@humanwhocodes/config-array@^0.11.10": + version "0.11.10" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.10.tgz#5a3ffe32cc9306365fb3fd572596cd602d5e12d2" + integrity sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@jest/expect-utils@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.5.0.tgz#f74fad6b6e20f924582dc8ecbf2cb800fe43a036" + integrity sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg== + dependencies: + jest-get-type "^29.4.3" + +"@jest/schemas@^29.4.3": + version "29.4.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.3.tgz#39cf1b8469afc40b6f5a2baaa146e332c4151788" + integrity sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg== + dependencies: + "@sinclair/typebox" "^0.25.16" + +"@jest/types@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.5.0.tgz#f59ef9b031ced83047c67032700d8c807d6e1593" + integrity sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog== + dependencies: + "@jest/schemas" "^29.4.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" + +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/source-map@^0.3.2": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.3.tgz#8108265659d4c33e72ffe14e33d6cc5eb59f2fda" + integrity sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/sourcemap-codec@1.4.14": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.18" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" + integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + +"@leichtgewicht/ip-codec@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" + integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== + +"@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": + version "5.1.1-v1" + resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129" + integrity sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg== + dependencies: + eslint-scope "5.1.1" + +"@nicolo-ribaudo/semver-v6@^6.3.3": + version "6.3.3" + resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz#ea6d23ade78a325f7a52750aab1526b02b628c29" + integrity sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@npmcli/fs@^1.0.0": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.1.1.tgz#72f719fe935e687c56a4faecf3c03d06ba593257" + integrity sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ== + dependencies: + "@gar/promisify" "^1.0.1" + semver "^7.3.5" + +"@npmcli/fs@^2.1.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-2.1.2.tgz#a9e2541a4a2fec2e69c29b35e6060973da79b865" + integrity sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ== + dependencies: + "@gar/promisify" "^1.1.3" + semver "^7.3.5" + +"@npmcli/move-file@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" + integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== + dependencies: + mkdirp "^1.0.4" + rimraf "^3.0.2" + +"@npmcli/move-file@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-2.0.1.tgz#26f6bdc379d87f75e55739bab89db525b06100e4" + integrity sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ== + dependencies: + mkdirp "^1.0.4" + rimraf "^3.0.2" + +"@reduxjs/toolkit@^1.9.5": + version "1.9.5" + resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.9.5.tgz#d3987849c24189ca483baa7aa59386c8e52077c4" + integrity sha512-Rt97jHmfTeaxL4swLRNPD/zV4OxTes4la07Xc4hetpUW/vc75t5m1ANyxG6ymnEQ2FsLQsoMlYB2vV1sO3m8tQ== + dependencies: + immer "^9.0.21" + redux "^4.2.1" + redux-thunk "^2.4.2" + reselect "^4.1.8" + +"@remix-run/router@1.7.2": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.7.2.tgz#cba1cf0a04bc04cb66027c51fa600e9cbc388bc8" + integrity sha512-7Lcn7IqGMV+vizMPoEl5F0XDshcdDYtMI6uJLQdQz5CfZAwy3vvGKYSUk789qndt5dEC4HfSjviSYlSoHGL2+A== + +"@rushstack/eslint-patch@^1.1.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz#8be36a1f66f3265389e90b5f9c9962146758f728" + integrity sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg== + +"@sinclair/typebox@^0.25.16": + version "0.25.24" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718" + integrity sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ== + +"@stellar/design-system@^1.0.0-beta.14": + version "1.0.0-beta.14" + resolved "https://registry.yarnpkg.com/@stellar/design-system/-/design-system-1.0.0-beta.14.tgz#56914f4d575eb93b65129ec280f077e845fb6cce" + integrity sha512-51MpT/bg1ShJmbYnB17bphd8jSHCgqfTqudNInXGEM2BcXwH8PQWFDIgQ07jD6wIvOGhRAktyYNE7wQv1X2O2w== + dependencies: + "@floating-ui/dom" "^1.2.5" + bignumber.js "^9.1.1" + configurable-date-input-polyfill "^3.1.5" + react-copy-to-clipboard "^5.1.0" + tslib "^2.5.0" + +"@stellar/tsconfig@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@stellar/tsconfig/-/tsconfig-1.0.2.tgz#18e9b1a1d6076e116bb405d11fc034401155292d" + integrity sha512-lC51QSlYRM8K3oGe0/WGPq+p9+u+yPzwZXSKrZXKOe4sq79vzfiqFbQyp5enOffFzXlahcDyTgY67mBOkJytfw== + +"@svgr/babel-plugin-add-jsx-attribute@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz#4001f5d5dd87fa13303e36ee106e3ff3a7eb8b22" + integrity sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g== + +"@svgr/babel-plugin-remove-jsx-attribute@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz#69177f7937233caca3a1afb051906698f2f59186" + integrity sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA== + +"@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz#c2c48104cfd7dcd557f373b70a56e9e3bdae1d44" + integrity sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA== + +"@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz#8fbb6b2e91fa26ac5d4aa25c6b6e4f20f9c0ae27" + integrity sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ== + +"@svgr/babel-plugin-svg-dynamic-title@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz#1d5ba1d281363fc0f2f29a60d6d936f9bbc657b0" + integrity sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og== + +"@svgr/babel-plugin-svg-em-dimensions@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz#35e08df300ea8b1d41cb8f62309c241b0369e501" + integrity sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g== + +"@svgr/babel-plugin-transform-react-native-svg@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.0.0.tgz#023cd0895b98521f566060d6bb92100b9fee3775" + integrity sha512-UKrY3860AQICgH7g+6h2zkoxeVEPLYwX/uAjmqo4PIq2FIHppwhIqZstIyTz0ZtlwreKR41O3W3BzsBBiJV2Aw== + +"@svgr/babel-plugin-transform-svg-component@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz#013b4bfca88779711f0ed2739f3f7efcefcf4f7e" + integrity sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw== + +"@svgr/babel-preset@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-preset/-/babel-preset-8.0.0.tgz#6d78100b3b6daf11c940b82d5bd8c3164b9c6ad9" + integrity sha512-KLcjiZychInVrhs86OvcYPLTFu9L5XV2vj0XAaE1HwE3J3jLmIzRY8ttdeAg/iFyp8nhavJpafpDZTt+1LIpkQ== + dependencies: + "@svgr/babel-plugin-add-jsx-attribute" "8.0.0" + "@svgr/babel-plugin-remove-jsx-attribute" "8.0.0" + "@svgr/babel-plugin-remove-jsx-empty-expression" "8.0.0" + "@svgr/babel-plugin-replace-jsx-attribute-value" "8.0.0" + "@svgr/babel-plugin-svg-dynamic-title" "8.0.0" + "@svgr/babel-plugin-svg-em-dimensions" "8.0.0" + "@svgr/babel-plugin-transform-react-native-svg" "8.0.0" + "@svgr/babel-plugin-transform-svg-component" "8.0.0" + +"@svgr/core@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/core/-/core-8.0.0.tgz#e96829cdb0473345d5671568282ee0736e86ef12" + integrity sha512-aJKtc+Pie/rFYsVH/unSkDaZGvEeylNv/s2cP+ta9/rYWxRVvoV/S4Qw65Kmrtah4CBK5PM6ISH9qUH7IJQCng== + dependencies: + "@babel/core" "^7.21.3" + "@svgr/babel-preset" "8.0.0" + camelcase "^6.2.0" + cosmiconfig "^8.1.3" + snake-case "^3.0.4" + +"@svgr/hast-util-to-babel-ast@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz#6952fd9ce0f470e1aded293b792a2705faf4ffd4" + integrity sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q== + dependencies: + "@babel/types" "^7.21.3" + entities "^4.4.0" + +"@svgr/plugin-jsx@8.0.1": + version "8.0.1" + resolved "https://registry.yarnpkg.com/@svgr/plugin-jsx/-/plugin-jsx-8.0.1.tgz#b9495e06062cc0cac0e035751b69471ee328236b" + integrity sha512-bfCFb+4ZsM3UuKP2t7KmDwn6YV8qVn9HIQJmau6xeQb/iV65Rpi7NBNBWA2hcCd4GKoCqG8hpaaDk5FDR0eH+g== + dependencies: + "@babel/core" "^7.21.3" + "@svgr/babel-preset" "8.0.0" + "@svgr/hast-util-to-babel-ast" "8.0.0" + svg-parser "^2.0.4" + +"@svgr/plugin-svgo@8.0.1": + version "8.0.1" + resolved "https://registry.yarnpkg.com/@svgr/plugin-svgo/-/plugin-svgo-8.0.1.tgz#df0199313fdc88c3d7cd8e0dff16695e9718548c" + integrity sha512-29OJ1QmJgnohQHDAgAuY2h21xWD6TZiXji+hnx+W635RiXTAlHTbjrZDktfqzkN0bOeQEtNe+xgq73/XeWFfSg== + dependencies: + cosmiconfig "^8.1.3" + deepmerge "^4.3.1" + svgo "^3.0.2" + +"@svgr/webpack@8.0.1": + version "8.0.1" + resolved "https://registry.yarnpkg.com/@svgr/webpack/-/webpack-8.0.1.tgz#a0e4a711daae347b515335449d198a275b3ab1e4" + integrity sha512-zSoeKcbCmfMXjA11uDuCJb+1LWNb3vy6Qw/VHj0Nfcl3UuqwuoZWknHsBIhCWvi4wU9vPui3aq054qjVyZqY4A== + dependencies: + "@babel/core" "^7.21.3" + "@babel/plugin-transform-react-constant-elements" "^7.21.3" + "@babel/preset-env" "^7.20.2" + "@babel/preset-react" "^7.18.6" + "@babel/preset-typescript" "^7.21.0" + "@svgr/core" "8.0.0" + "@svgr/plugin-jsx" "8.0.1" + "@svgr/plugin-svgo" "8.0.1" + +"@tanstack/eslint-plugin-query@^4.29.25": + version "4.29.25" + resolved "https://registry.yarnpkg.com/@tanstack/eslint-plugin-query/-/eslint-plugin-query-4.29.25.tgz#422693f8a08d3dc98ca22135913b9a36ae51510c" + integrity sha512-wn+My+vBVTH/BZouf5syhUiUrCYiuAwRdepO/gjn6BBwYyN7XQ8cS/ooO0h2ut0h1G3UO52q26An8jYJCjR29w== + +"@tanstack/query-core@4.29.25": + version "4.29.25" + resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.29.25.tgz#605d357968a740544af6754004eed1dfd4587cb8" + integrity sha512-DI4y4VC6Uw4wlTpOocEXDky69xeOScME1ezLKsj+hOk7DguC9fkqXtp6Hn39BVb9y0b5IBrY67q6kIX623Zj4Q== + +"@tanstack/react-query@^4.29.25": + version "4.29.25" + resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.29.25.tgz#64df3260b65760fbd3c81ffae23b7b3802c71aa6" + integrity sha512-c1+Ezu+XboYrdAMdusK2fTdRqXPMgPAnyoTrzHOZQqr8Hqz6PNvV9DSKl8agUo6nXX4np7fdWabIprt+838dLg== + dependencies: + "@tanstack/query-core" "4.29.25" + use-sync-external-store "^1.2.0" + +"@testing-library/dom@^9.0.0": + version "9.2.0" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-9.2.0.tgz#0e1f45e956f2a16f471559c06edd8827c4832f04" + integrity sha512-xTEnpUKiV/bMyEsE5bT4oYA0x0Z/colMtxzUY8bKyPXBNLn/e0V4ZjBZkEhms0xE4pv9QsPfSRu9AWS4y5wGvA== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/runtime" "^7.12.5" + "@types/aria-query" "^5.0.1" + aria-query "^5.0.0" + chalk "^4.1.0" + dom-accessibility-api "^0.5.9" + lz-string "^1.5.0" + pretty-format "^27.0.2" + +"@testing-library/jest-dom@^5.17.0": + version "5.17.0" + resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz#5e97c8f9a15ccf4656da00fecab505728de81e0c" + integrity sha512-ynmNeT7asXyH3aSVv4vvX4Rb+0qjOhdNHnO/3vuZNqPmhDpV/+rCSGwQ7bLcmU2cJ4dvoheIO85LQj0IbJHEtg== + dependencies: + "@adobe/css-tools" "^4.0.1" + "@babel/runtime" "^7.9.2" + "@types/testing-library__jest-dom" "^5.9.1" + aria-query "^5.0.0" + chalk "^3.0.0" + css.escape "^1.5.1" + dom-accessibility-api "^0.5.6" + lodash "^4.17.15" + redent "^3.0.0" + +"@testing-library/react@^14.0.0": + version "14.0.0" + resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-14.0.0.tgz#59030392a6792450b9ab8e67aea5f3cc18d6347c" + integrity sha512-S04gSNJbYE30TlIMLTzv6QCTzt9AqIF5y6s6SzVFILNcNvbV/jU96GeiTPillGQo+Ny64M/5PV7klNYYgv5Dfg== + dependencies: + "@babel/runtime" "^7.12.5" + "@testing-library/dom" "^9.0.0" + "@types/react-dom" "^18.0.0" + +"@testing-library/user-event@^14.4.3": + version "14.4.3" + resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.4.3.tgz#af975e367743fa91989cd666666aec31a8f50591" + integrity sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q== + +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + +"@tootallnate/once@2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" + integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== + +"@trysound/sax@0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" + integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== + +"@types/aria-query@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.1.tgz#3286741fb8f1e1580ac28784add4c7a1d49bdfbc" + integrity sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q== + +"@types/body-parser@*": + version "1.19.2" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" + integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/bonjour@^3.5.9": + version "3.5.10" + resolved "https://registry.yarnpkg.com/@types/bonjour/-/bonjour-3.5.10.tgz#0f6aadfe00ea414edc86f5d106357cda9701e275" + integrity sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw== + dependencies: + "@types/node" "*" + +"@types/connect-history-api-fallback@^1.3.5": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz#d1f7a8a09d0ed5a57aee5ae9c18ab9b803205dae" + integrity sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw== + dependencies: + "@types/express-serve-static-core" "*" + "@types/node" "*" + +"@types/connect@*": + version "3.4.35" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" + integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== + dependencies: + "@types/node" "*" + +"@types/eslint-scope@^3.7.3": + version "3.7.4" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16" + integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*", "@types/eslint@^8.37.0": + version "8.37.0" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.37.0.tgz#29cebc6c2a3ac7fea7113207bf5a828fdf4d7ef1" + integrity sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2" + integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ== + +"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33": + version "4.17.33" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz#de35d30a9d637dc1450ad18dd583d75d5733d543" + integrity sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + +"@types/express@*", "@types/express@^4.17.13": + version "4.17.17" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.17.tgz#01d5437f6ef9cfa8668e616e13c2f2ac9a491ae4" + integrity sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.33" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/glob@^7.1.1": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" + integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + +"@types/history@^4.7.11": + version "4.7.11" + resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64" + integrity sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA== + +"@types/hoist-non-react-statics@^3.3.0", "@types/hoist-non-react-statics@^3.3.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" + integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== + dependencies: + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + +"@types/html-minifier-terser@^6.0.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35" + integrity sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg== + +"@types/http-proxy@^1.17.8": + version "1.17.10" + resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.10.tgz#e576c8e4a0cc5c6a138819025a88e167ebb38d6c" + integrity sha512-Qs5aULi+zV1bwKAg5z1PWnDXWmsn+LxIvUGv6E2+OOMYhclZMO+OXd9pYVf2gLykf2I7IV2u7oTHwChPNsvJ7g== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@*": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.0.tgz#337b90bbcfe42158f39c2fb5619ad044bbb518ac" + integrity sha512-3Emr5VOl/aoBwnWcH/EFQvlSAmjV+XtV9GGu5mwdYew5vhQh0IUZx/60x0TzHDu09Bi7HMx10t/namdJw5QIcg== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/jest@^29.5.3": + version "29.5.3" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.3.tgz#7a35dc0044ffb8b56325c6802a4781a626b05777" + integrity sha512-1Nq7YrO/vJE/FYnqYyw0FS8LdrjExSgIiHyKg7xPpn+yi8Q4huZryKnkJatN1ZRH89Kw2v33/8ZMB7DuZeSLlA== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/json-schema@*", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + +"@types/json-schema@^7.0.12": + version "7.0.12" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" + integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== + +"@types/lodash@^4.14.195": + version "4.14.195" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.195.tgz#bafc975b252eb6cea78882ce8a7b6bf22a6de632" + integrity sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg== + +"@types/mime@*": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" + integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== + +"@types/minimatch@*": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" + integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== + +"@types/minimatch@^3.0.3": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" + integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== + +"@types/minimist@^1.2.0": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" + integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== + +"@types/node@*": + version "18.15.11" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.11.tgz#b3b790f09cb1696cffcec605de025b088fa4225f" + integrity sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q== + +"@types/node@^20.4.2": + version "20.4.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.2.tgz#129cc9ae69f93824f92fac653eebfb4812ab4af9" + integrity sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw== + +"@types/normalize-package-data@^2.4.0": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" + integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== + +"@types/papaparse@^5.3.7": + version "5.3.7" + resolved "https://registry.yarnpkg.com/@types/papaparse/-/papaparse-5.3.7.tgz#8d3bf9e62ac2897df596f49d9ca59a15451aa247" + integrity sha512-f2HKmlnPdCvS0WI33WtCs5GD7X1cxzzS/aduaxSu3I7TbhWlENjSPs6z5TaB9K0J+BH1jbmqTaM+ja5puis4wg== + dependencies: + "@types/node" "*" + +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + +"@types/prop-types@*": + version "15.7.5" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" + integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== + +"@types/qs@*": + version "6.9.7" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" + integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== + +"@types/range-parser@*": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" + integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== + +"@types/react-dom@^18.0.0": + version "18.0.11" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.11.tgz#321351c1459bc9ca3d216aefc8a167beec334e33" + integrity sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw== + dependencies: + "@types/react" "*" + +"@types/react-dom@^18.2.7": + version "18.2.7" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.7.tgz#67222a08c0a6ae0a0da33c3532348277c70abb63" + integrity sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA== + dependencies: + "@types/react" "*" + +"@types/react-google-recaptcha@^2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@types/react-google-recaptcha/-/react-google-recaptcha-2.1.5.tgz#af157dc2e4bde3355f9b815a64f90e85cfa9df8b" + integrity sha512-iWTjmVttlNgp0teyh7eBXqNOQzVq2RWNiFROWjraOptRnb1OcHJehQnji0sjqIRAk9K0z8stjyhU+OLpPb0N6w== + dependencies: + "@types/react" "*" + +"@types/react-redux@^7.1.25": + version "7.1.25" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.25.tgz#de841631205b24f9dfb4967dd4a7901e048f9a88" + 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" + +"@types/react-router-dom@^5.3.3": + version "5.3.3" + resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.3.3.tgz#e9d6b4a66fcdbd651a5f106c2656a30088cc1e83" + integrity sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw== + dependencies: + "@types/history" "^4.7.11" + "@types/react" "*" + "@types/react-router" "*" + +"@types/react-router@*": + version "5.1.20" + resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.20.tgz#88eccaa122a82405ef3efbcaaa5dcdd9f021387c" + integrity sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q== + dependencies: + "@types/history" "^4.7.11" + "@types/react" "*" + +"@types/react@*": + version "18.0.37" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.37.tgz#7a784e2a8b8f83abb04dc6b9ed9c9b4c0aee9be7" + integrity sha512-4yaZZtkRN3ZIQD3KSEwkfcik8s0SWV+82dlJot1AbGYHCzJkWP3ENBY6wYeDRmKZ6HkrgoGAmR2HqdwYGp6OEw== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/react@^18.2.15": + version "18.2.15" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.15.tgz#14792b35df676c20ec3cf595b262f8c615a73066" + integrity sha512-oEjE7TQt1fFTFSbf8kkNuc798ahTUzn3Le67/PWjE8MAfYAD/qB7O8hSTcromLFqHCt9bcdOg5GXMokzTjJ5SA== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/retry@0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" + integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== + +"@types/scheduler@*": + version "0.16.3" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5" + integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ== + +"@types/semver@^7.3.12": + version "7.3.13" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" + integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== + +"@types/semver@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a" + integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw== + +"@types/serve-index@^1.9.1": + version "1.9.1" + resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.1.tgz#1b5e85370a192c01ec6cec4735cf2917337a6278" + integrity sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg== + dependencies: + "@types/express" "*" + +"@types/serve-static@*", "@types/serve-static@^1.13.10": + version "1.15.1" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.1.tgz#86b1753f0be4f9a1bee68d459fcda5be4ea52b5d" + integrity sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ== + dependencies: + "@types/mime" "*" + "@types/node" "*" + +"@types/sockjs@^0.3.33": + version "0.3.33" + resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.33.tgz#570d3a0b99ac995360e3136fd6045113b1bd236f" + integrity sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw== + dependencies: + "@types/node" "*" + +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + +"@types/testing-library__jest-dom@^5.9.1": + version "5.14.5" + resolved "https://registry.yarnpkg.com/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.5.tgz#d113709c90b3c75fdb127ec338dad7d5f86c974f" + integrity sha512-SBwbxYoyPIvxHbeHxTZX2Pe/74F/tX2/D3mMvzabdeJ25bBojfW0TyB8BHrbq/9zaaKICJZjLP+8r6AeZMFCuQ== + dependencies: + "@types/jest" "*" + +"@types/use-sync-external-store@^0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43" + integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA== + +"@types/uuid@^9.0.2": + version "9.0.2" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.2.tgz#ede1d1b1e451548d44919dc226253e32a6952c4b" + integrity sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ== + +"@types/ws@^8.5.5": + version "8.5.5" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.5.tgz#af587964aa06682702ee6dcbc7be41a80e4b28eb" + integrity sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg== + dependencies: + "@types/node" "*" + +"@types/yargs-parser@*": + version "21.0.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" + integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== + +"@types/yargs@^17.0.8": + version "17.0.24" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.24.tgz#b3ef8d50ad4aa6aecf6ddc97c580a00f5aa11902" + integrity sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw== + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@^5.5.0": + version "5.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.0.tgz#c0e10eeb936debe5d1c3433cf36206a95befefd0" + integrity sha512-p0QgrEyrxAWBecR56gyn3wkG15TJdI//eetInP3zYRewDh0XS+DhB3VUAd3QqvziFsfaQIoIuZMxZRB7vXYaYw== + dependencies: + "@eslint-community/regexpp" "^4.4.0" + "@typescript-eslint/scope-manager" "5.59.0" + "@typescript-eslint/type-utils" "5.59.0" + "@typescript-eslint/utils" "5.59.0" + debug "^4.3.4" + grapheme-splitter "^1.0.4" + ignore "^5.2.0" + natural-compare-lite "^1.4.0" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/eslint-plugin@^6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.1.0.tgz#96f3ca6615717659d06c9f7161a1d14ab0c49c66" + integrity sha512-qg7Bm5TyP/I7iilGyp6DRqqkt8na00lI6HbjWZObgk3FFSzH5ypRwAHXJhJkwiRtTcfn+xYQIMOR5kJgpo6upw== + dependencies: + "@eslint-community/regexpp" "^4.5.1" + "@typescript-eslint/scope-manager" "6.1.0" + "@typescript-eslint/type-utils" "6.1.0" + "@typescript-eslint/utils" "6.1.0" + "@typescript-eslint/visitor-keys" "6.1.0" + debug "^4.3.4" + graphemer "^1.4.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + natural-compare-lite "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/experimental-utils@^5.0.0": + version "5.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.59.0.tgz#ef5c78ba1f33853add4f4d7ac5a215e90c9e1409" + integrity sha512-evvdzcPrUv9+Hj+KX6fa3WMrtTZ7onnGHL3NfT/zN9q2FQhb2yvNJDa+w/ND0TpdRCbulwag0dxwMUt2MJB2Vg== + dependencies: + "@typescript-eslint/utils" "5.59.0" + +"@typescript-eslint/parser@^5.5.0": + version "5.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.0.tgz#0ad7cd019346cc5d150363f64869eca10ca9977c" + integrity sha512-qK9TZ70eJtjojSUMrrEwA9ZDQ4N0e/AuoOIgXuNBorXYcBDk397D2r5MIe1B3cok/oCtdNC5j+lUUpVB+Dpb+w== + dependencies: + "@typescript-eslint/scope-manager" "5.59.0" + "@typescript-eslint/types" "5.59.0" + "@typescript-eslint/typescript-estree" "5.59.0" + debug "^4.3.4" + +"@typescript-eslint/parser@^6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.1.0.tgz#3135bf65dca5340d8650703eb8cb83113e156ee5" + integrity sha512-hIzCPvX4vDs4qL07SYzyomamcs2/tQYXg5DtdAfj35AyJ5PIUqhsLf4YrEIFzZcND7R2E8tpQIZKayxg8/6Wbw== + dependencies: + "@typescript-eslint/scope-manager" "6.1.0" + "@typescript-eslint/types" "6.1.0" + "@typescript-eslint/typescript-estree" "6.1.0" + "@typescript-eslint/visitor-keys" "6.1.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@5.59.0": + version "5.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.0.tgz#86501d7a17885710b6716a23be2e93fc54a4fe8c" + integrity sha512-tsoldKaMh7izN6BvkK6zRMINj4Z2d6gGhO2UsI8zGZY3XhLq1DndP3Ycjhi1JwdwPRwtLMW4EFPgpuKhbCGOvQ== + dependencies: + "@typescript-eslint/types" "5.59.0" + "@typescript-eslint/visitor-keys" "5.59.0" + +"@typescript-eslint/scope-manager@6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.1.0.tgz#a6cdbe11630614f8c04867858a42dd56590796ed" + integrity sha512-AxjgxDn27hgPpe2rQe19k0tXw84YCOsjDJ2r61cIebq1t+AIxbgiXKvD4999Wk49GVaAcdJ/d49FYel+Pp3jjw== + dependencies: + "@typescript-eslint/types" "6.1.0" + "@typescript-eslint/visitor-keys" "6.1.0" + +"@typescript-eslint/type-utils@5.59.0": + version "5.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.0.tgz#8e8d1420fc2265989fa3a0d897bde37f3851e8c9" + integrity sha512-d/B6VSWnZwu70kcKQSCqjcXpVH+7ABKH8P1KNn4K7j5PXXuycZTPXF44Nui0TEm6rbWGi8kc78xRgOC4n7xFgA== + dependencies: + "@typescript-eslint/typescript-estree" "5.59.0" + "@typescript-eslint/utils" "5.59.0" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/type-utils@6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.1.0.tgz#21cc6c3bc1980b03f9eb4e64580d0c5be6f08215" + integrity sha512-kFXBx6QWS1ZZ5Ni89TyT1X9Ag6RXVIVhqDs0vZE/jUeWlBv/ixq2diua6G7ece6+fXw3TvNRxP77/5mOMusx2w== + dependencies: + "@typescript-eslint/typescript-estree" "6.1.0" + "@typescript-eslint/utils" "6.1.0" + debug "^4.3.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/types@5.59.0": + version "5.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.0.tgz#3fcdac7dbf923ec5251545acdd9f1d42d7c4fe32" + integrity sha512-yR2h1NotF23xFFYKHZs17QJnB51J/s+ud4PYU4MqdZbzeNxpgUr05+dNeCN/bb6raslHvGdd6BFCkVhpPk/ZeA== + +"@typescript-eslint/types@6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.1.0.tgz#2d607c62827bb416ada5c96ebfa2ef84e45a8dfa" + integrity sha512-+Gfd5NHCpDoHDOaU/yIF3WWRI2PcBRKKpP91ZcVbL0t5tQpqYWBs3z/GGhvU+EV1D0262g9XCnyqQh19prU0JQ== + +"@typescript-eslint/typescript-estree@5.59.0": + version "5.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.0.tgz#8869156ee1dcfc5a95be3ed0e2809969ea28e965" + integrity sha512-sUNnktjmI8DyGzPdZ8dRwW741zopGxltGs/SAPgGL/AAgDpiLsCFLcMNSpbfXfmnNeHmK9h3wGmCkGRGAoUZAg== + dependencies: + "@typescript-eslint/types" "5.59.0" + "@typescript-eslint/visitor-keys" "5.59.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/typescript-estree@6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.1.0.tgz#ea382f6482ba698d7e993a88ce5391ea7a66c33d" + integrity sha512-nUKAPWOaP/tQjU1IQw9sOPCDavs/iU5iYLiY/6u7gxS7oKQoi4aUxXS1nrrVGTyBBaGesjkcwwHkbkiD5eBvcg== + dependencies: + "@typescript-eslint/types" "6.1.0" + "@typescript-eslint/visitor-keys" "6.1.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/utils@5.59.0", "@typescript-eslint/utils@^5.58.0": + version "5.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.0.tgz#063d066b3bc4850c18872649ed0da9ee72d833d5" + integrity sha512-GGLFd+86drlHSvPgN/el6dRQNYYGOvRSDVydsUaQluwIW3HvbXuxyuD5JETvBt/9qGYe+lOrDk6gRrWOHb/FvA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.59.0" + "@typescript-eslint/types" "5.59.0" + "@typescript-eslint/typescript-estree" "5.59.0" + eslint-scope "^5.1.1" + semver "^7.3.7" + +"@typescript-eslint/utils@6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.1.0.tgz#1641843792b4e3451cc692e2c73055df8b26f453" + integrity sha512-wp652EogZlKmQoMS5hAvWqRKplXvkuOnNzZSE0PVvsKjpexd/XznRVHAtrfHFYmqaJz0DFkjlDsGYC9OXw+OhQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "6.1.0" + "@typescript-eslint/types" "6.1.0" + "@typescript-eslint/typescript-estree" "6.1.0" + semver "^7.5.4" + +"@typescript-eslint/visitor-keys@5.59.0": + version "5.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.0.tgz#a59913f2bf0baeb61b5cfcb6135d3926c3854365" + integrity sha512-qZ3iXxQhanchCeaExlKPV3gDQFxMUmU35xfd5eCXB6+kUw1TUAbIy2n7QIrwz9s98DQLzNWyHp61fY0da4ZcbA== + dependencies: + "@typescript-eslint/types" "5.59.0" + eslint-visitor-keys "^3.3.0" + +"@typescript-eslint/visitor-keys@6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.1.0.tgz#d2b84dff6b58944d3257ea03687e269a788c73be" + integrity sha512-yQeh+EXhquh119Eis4k0kYhj9vmFzNpbhM3LftWQVwqVjipCkwHBQOZutcYW+JVkjtTG9k8nrZU1UoNedPDd1A== + dependencies: + "@typescript-eslint/types" "6.1.0" + eslint-visitor-keys "^3.4.1" + +"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24" + integrity sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + +"@webassemblyjs/floating-point-hex-parser@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" + integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== + +"@webassemblyjs/helper-api-error@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" + integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== + +"@webassemblyjs/helper-buffer@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz#b66d73c43e296fd5e88006f18524feb0f2c7c093" + integrity sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA== + +"@webassemblyjs/helper-numbers@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" + integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" + integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== + +"@webassemblyjs/helper-wasm-section@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz#ff97f3863c55ee7f580fd5c41a381e9def4aa577" + 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" + +"@webassemblyjs/ieee754@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" + integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" + integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" + integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== + +"@webassemblyjs/wasm-edit@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz#c72fa8220524c9b416249f3d94c2958dfe70ceab" + 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" + +"@webassemblyjs/wasm-gen@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz#fb5283e0e8b4551cc4e9c3c0d7184a65faf7c268" + 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" + +"@webassemblyjs/wasm-opt@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz#d9a22d651248422ca498b09aa3232a81041487c2" + 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" + +"@webassemblyjs/wasm-parser@1.11.6", "@webassemblyjs/wasm-parser@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz#bb85378c527df824004812bbdb784eea539174a1" + 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" + +"@webassemblyjs/wast-printer@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz#a7bf8dd7e362aeb1668ff43f35cb849f188eff20" + integrity sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@xtuc/long" "4.2.2" + +"@webpack-cli/configtest@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-2.1.1.tgz#3b2f852e91dac6e3b85fb2a314fb8bef46d94646" + integrity sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw== + +"@webpack-cli/info@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-2.0.2.tgz#cc3fbf22efeb88ff62310cf885c5b09f44ae0fdd" + integrity sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A== + +"@webpack-cli/serve@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e" + integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ== + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +acorn-import-assertions@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" + integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.5.0, acorn@^8.7.1: + version "8.8.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" + integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== + +acorn@^8.9.0: + version "8.10.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" + integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== + +agent-base@6, agent-base@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +agentkeepalive@^4.1.3, agentkeepalive@^4.2.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.3.0.tgz#bb999ff07412653c1803b3ced35e50729830a255" + integrity sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg== + dependencies: + debug "^4.1.0" + depd "^2.0.0" + humanize-ms "^1.2.1" + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + +ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv-keywords@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== + dependencies: + fast-deep-equal "^3.1.3" + +ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + 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" + +ajv@^8.0.0, ajv@^8.9.0: + version "8.12.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" + 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" + +ansi-escapes@^4.3.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-html-community@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41" + integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +ansi-styles@^6.0.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +"aproba@^1.0.3 || ^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" + integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== + +are-we-there-yet@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz#679df222b278c64f2cdba1175cdc00b0d96164bd" + integrity sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +aria-query@^5.0.0, aria-query@^5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.1.3.tgz#19db27cd101152773631396f7a95a3b58c22c35e" + integrity sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ== + dependencies: + deep-equal "^2.0.5" + +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + dependencies: + call-bind "^1.0.2" + is-array-buffer "^3.0.1" + +array-differ@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" + integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +array-flatten@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + +array-includes@^3.1.5, array-includes@^3.1.6: + version "3.1.6" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f" + integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + get-intrinsic "^1.1.3" + is-string "^1.0.7" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng== + dependencies: + array-uniq "^1.0.1" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q== + +array.prototype.flat@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz#ffc6576a7ca3efc2f46a143b9d1dda9b4b3cf5e2" + integrity sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-shim-unscopables "^1.0.0" + +array.prototype.flatmap@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183" + integrity sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-shim-unscopables "^1.0.0" + +array.prototype.tosorted@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz#ccf44738aa2b5ac56578ffda97c03fd3e23dd532" + integrity sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-shim-unscopables "^1.0.0" + get-intrinsic "^1.1.3" + +arrify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== + +arrify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" + integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== + +asn1.js@^5.2.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" + integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + safer-buffer "^2.1.0" + +assert@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-2.0.0.tgz#95fc1c616d48713510680f2eaf2d10dd22e02d32" + integrity sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A== + dependencies: + es6-object-assign "^1.1.0" + is-nan "^1.2.1" + object-is "^1.0.1" + util "^0.12.0" + +ast-types-flow@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" + integrity sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag== + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +async-foreach@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" + integrity sha512-VUeSMD8nEGBWaZK4lizI1sf3yEC7pnAQ/mrI7pC2fBz2s/tq5jWWEngTwaf0Gruu/OoXRGLGg1XFqpYBiGTYJA== + +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + +axe-core@^4.6.2: + version "4.7.0" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf" + integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ== + +axobject-query@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.1.1.tgz#3b6e5c6d4e43ca7ba51c5babf99d22a9c68485e1" + integrity sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg== + dependencies: + deep-equal "^2.0.5" + +babel-plugin-macros@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" + integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg== + dependencies: + "@babel/runtime" "^7.12.5" + cosmiconfig "^7.0.0" + resolve "^1.19.0" + +babel-plugin-polyfill-corejs2@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz#5d1bd3836d0a19e1b84bbf2d9640ccb6f951c122" + integrity sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q== + dependencies: + "@babel/compat-data" "^7.17.7" + "@babel/helper-define-polyfill-provider" "^0.3.3" + semver "^6.1.1" + +babel-plugin-polyfill-corejs2@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.4.tgz#9f9a0e1cd9d645cc246a5e094db5c3aa913ccd2b" + integrity sha512-9WeK9snM1BfxB38goUEv2FLnA6ja07UMfazFHzCXUb3NyDZAwfXvQiURQ6guTTMeHcOsdknULm1PDhs4uWtKyA== + dependencies: + "@babel/compat-data" "^7.22.6" + "@babel/helper-define-polyfill-provider" "^0.4.1" + "@nicolo-ribaudo/semver-v6" "^6.3.3" + +babel-plugin-polyfill-corejs3@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz#56ad88237137eade485a71b52f72dbed57c6230a" + integrity sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.3" + core-js-compat "^3.25.1" + +babel-plugin-polyfill-corejs3@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.2.tgz#d406c5738d298cd9c66f64a94cf8d5904ce4cc5e" + integrity sha512-Cid+Jv1BrY9ReW9lIfNlNpsI53N+FN7gE+f73zLAUbr9C52W4gKLWSByx47pfDJsEysojKArqOtOKZSVIIUTuQ== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.4.1" + core-js-compat "^3.31.0" + +babel-plugin-polyfill-regenerator@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz#390f91c38d90473592ed43351e801a9d3e0fd747" + integrity sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.3" + +babel-plugin-polyfill-regenerator@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.1.tgz#ace7a5eced6dff7d5060c335c52064778216afd3" + integrity sha512-L8OyySuI6OSQ5hFy9O+7zFjyr4WhAfRjLIOkhQGYl+emwJkd/S4XXT1JpfrgR1jrQ1NcGiOh+yAdGlF8pnC3Jw== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.4.1" + +babel-plugin-transform-react-remove-prop-types@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz#f2edaf9b4c6a5fbe5c1d678bfb531078c1555f3a" + integrity sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA== + +babel-preset-react-app@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-react-app/-/babel-preset-react-app-10.0.1.tgz#ed6005a20a24f2c88521809fa9aea99903751584" + 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" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw== + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +bignumber.js@^9.1.1: + version "9.1.1" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.1.tgz#c4df7dc496bd849d4c9464344c1aa74228b4dac6" + integrity sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.0.0, bn.js@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + +body-parser@1.20.1: + version "1.20.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" + 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" + +bonjour-service@^1.0.11: + version "1.1.1" + resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.1.1.tgz#960948fa0e0153f5d26743ab15baf8e33752c135" + 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" + +boolbase@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +brorand@^1.0.1, brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" + integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== + dependencies: + bn.js "^5.0.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" + integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== + dependencies: + bn.js "^5.1.1" + browserify-rsa "^4.0.1" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.3" + inherits "^2.0.4" + parse-asn1 "^5.1.5" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +browserslist@^4.14.5, browserslist@^4.21.3, browserslist@^4.21.5: + version "4.21.5" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.5.tgz#75c5dae60063ee641f977e00edd3cfb2fb7af6a7" + integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w== + dependencies: + caniuse-lite "^1.0.30001449" + electron-to-chromium "^1.4.284" + node-releases "^2.0.8" + update-browserslist-db "^1.0.10" + +browserslist@^4.21.9: + version "4.21.9" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.9.tgz#e11bdd3c313d7e2a9e87e8b4b0c7872b13897635" + integrity sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg== + dependencies: + caniuse-lite "^1.0.30001503" + electron-to-chromium "^1.4.431" + node-releases "^2.0.12" + update-browserslist-db "^1.0.11" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== + +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ== + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +cacache@^15.2.0: + version "15.3.0" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" + integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== + 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" + +cacache@^16.1.0: + version "16.1.3" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-16.1.3.tgz#a02b9f34ecfaf9a78c9f4bc16fceb94d5d67a38e" + integrity sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ== + dependencies: + "@npmcli/fs" "^2.1.0" + "@npmcli/move-file" "^2.0.0" + chownr "^2.0.0" + fs-minipass "^2.1.0" + glob "^8.0.1" + infer-owner "^1.0.4" + lru-cache "^7.7.1" + minipass "^3.1.6" + minipass-collect "^1.0.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + mkdirp "^1.0.4" + p-map "^4.0.0" + promise-inflight "^1.0.1" + rimraf "^3.0.2" + ssri "^9.0.0" + tar "^6.1.11" + unique-filename "^2.0.0" + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camel-case@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" + integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== + dependencies: + pascal-case "^3.1.2" + tslib "^2.0.3" + +camelcase-keys@^6.2.2: + version "6.2.2" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" + integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg== + dependencies: + camelcase "^5.3.1" + map-obj "^4.0.0" + quick-lru "^4.0.1" + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001449: + version "1.0.30001480" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001480.tgz#9bbd35ee44c2480a1e3a3b9f4496f5066817164a" + integrity sha512-q7cpoPPvZYgtyC4VaBSN0Bt+PJ4c4EYRf0DrduInOz2SkFpHD5p3LnvEpqBp7UnJn+8x1Ogl1s38saUxe+ihQQ== + +caniuse-lite@^1.0.30001503: + version "1.0.30001517" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001517.tgz#90fabae294215c3495807eb24fc809e11dc2f0a8" + integrity sha512-Vdhm5S11DaFVLlyiKu4hiUTkpZu+y1KA/rZZqVQfOD5YdDT/eQKlkt7NaE0WGOFgX32diqt9MiP9CAiFeRklaA== + +chalk@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.2.0.tgz#249623b7d66869c673699fb66d65723e54dfcfb3" + integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA== + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + 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" + +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +"chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + 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" + optionalDependencies: + fsevents "~2.3.2" + +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +ci-info@^3.2.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" + integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +clean-css@^5.2.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.2.tgz#70ecc7d4d4114921f5d298349ff86a31a9975224" + integrity sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww== + dependencies: + source-map "~0.6.0" + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +clean-webpack-plugin@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/clean-webpack-plugin/-/clean-webpack-plugin-4.0.0.tgz#72947d4403d452f38ed61a9ff0ada8122aacd729" + integrity sha512-WuWE1nyTNAyW5T7oNyys2EN0cfP2fdRxhxnIQWiAp0bMabPdHhoGxM8A6YL2GhqwgrPnnaemVE7nv5XJ2Fhh2w== + dependencies: + del "^4.1.1" + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-truncate@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" + integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== + dependencies: + slice-ansi "^3.0.0" + string-width "^4.2.0" + +cli-truncate@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-3.1.0.tgz#3f23ab12535e3d73e839bb43e73c9de487db1389" + integrity sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA== + dependencies: + slice-ansi "^5.0.0" + string-width "^5.0.0" + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-support@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + +colorette@^2.0.10, colorette@^2.0.14, colorette@^2.0.19: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +commander@^10.0.0, commander@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + +commander@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + 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" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +concurrently@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-8.2.0.tgz#cdc9f621a4d913366600355d68254df2c5e782f3" + integrity sha512-nnLMxO2LU492mTUj9qX/az/lESonSZu81UznYDoXtz1IQf996ixVqPAgHXwvHiHCAef/7S8HIK+fTFK7Ifk8YA== + dependencies: + chalk "^4.1.2" + date-fns "^2.30.0" + lodash "^4.17.21" + rxjs "^7.8.1" + shell-quote "^1.8.1" + spawn-command "0.0.2" + supports-color "^8.1.1" + tree-kill "^1.2.2" + yargs "^17.7.2" + +configurable-date-input-polyfill@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/configurable-date-input-polyfill/-/configurable-date-input-polyfill-3.1.5.tgz#97b03a20862e8222272c1572df9593748b3bb288" + integrity sha512-N077aVhmGm6naVPdSyOes+YrFds4CBrCBcWN4zq52Fz7vzQB62iGdkHRNSQE3KFjtMbSMoUrWzbh2oWHXf39og== + +confusing-browser-globals@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81" + integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA== + +connect-history-api-fallback@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8" + integrity sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA== + +console-control-strings@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +convert-source-map@^1.7.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" + integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== + +copy-to-clipboard@^3.3.1: + version "3.3.3" + resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz#55ac43a1db8ae639a4bd99511c148cdd1b83a1b0" + integrity sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA== + dependencies: + toggle-selection "^1.0.6" + +copy-webpack-plugin@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz#96d4dbdb5f73d02dd72d0528d1958721ab72e04a" + integrity sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ== + dependencies: + fast-glob "^3.2.11" + glob-parent "^6.0.1" + globby "^13.1.1" + normalize-path "^3.0.0" + schema-utils "^4.0.0" + serialize-javascript "^6.0.0" + +core-js-compat@^3.25.1: + version "3.30.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.30.1.tgz#961541e22db9c27fc48bfc13a3cafa8734171dfe" + integrity sha512-d690npR7MC6P0gq4npTl5n2VQeNAmUrJ90n+MHiKS7W2+xno4o3F5GDEuylSdi6EJ3VssibSGXOa1r3YXD3Mhw== + dependencies: + browserslist "^4.21.5" + +core-js-compat@^3.31.0: + version "3.31.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.31.1.tgz#5084ad1a46858df50ff89ace152441a63ba7aae0" + integrity sha512-wIDWd2s5/5aJSdpOJHfSibxNODxoGoWOBHt8JSPB41NOE94M7kuTPZCYLOlTtuoXTsBPKobpJ6T+y0SSy5L9SA== + dependencies: + browserslist "^4.21.9" + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" + 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" + +cosmiconfig@^8.1.3: + version "8.2.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.2.0.tgz#f7d17c56a590856cd1e7cee98734dca272b0d8fd" + integrity sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ== + dependencies: + import-fresh "^3.2.1" + js-yaml "^4.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + +create-ecdh@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" + integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== + dependencies: + bn.js "^4.1.0" + elliptic "^6.5.3" + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +crypto-browserify@^3.12.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +crypto-js@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.1.1.tgz#9e485bcf03521041bd85844786b83fb7619736cf" + integrity sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw== + +css-loader@^6.8.1: + version "6.8.1" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.8.1.tgz#0f8f52699f60f5e679eab4ec0fcd68b8e8a50a88" + 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" + +css-select@^4.1.3: + version "4.3.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b" + 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" + +css-select@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-5.1.0.tgz#b8ebd6554c3637ccc76688804ad3f6a6fdaea8a6" + integrity sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg== + dependencies: + boolbase "^1.0.0" + css-what "^6.1.0" + domhandler "^5.0.2" + domutils "^3.0.1" + nth-check "^2.0.1" + +css-tree@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.3.1.tgz#10264ce1e5442e8572fc82fbe490644ff54b5c20" + integrity sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw== + dependencies: + mdn-data "2.0.30" + source-map-js "^1.0.1" + +css-tree@~2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.2.1.tgz#36115d382d60afd271e377f9c5f67d02bd48c032" + integrity sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA== + dependencies: + mdn-data "2.0.28" + source-map-js "^1.0.1" + +css-what@^6.0.1, css-what@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" + integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== + +css.escape@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" + integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg== + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +csso@^5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/csso/-/csso-5.0.5.tgz#f9b7fe6cc6ac0b7d90781bb16d5e9874303e2ca6" + integrity sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ== + dependencies: + css-tree "~2.2.0" + +csstype@^3.0.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" + integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== + +damerau-levenshtein@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" + integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== + +date-fns@^2.30.0: + version "2.30.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0" + integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw== + dependencies: + "@babel/runtime" "^7.21.0" + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +decamelize-keys@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.1.tgz#04a2d523b2f18d80d0158a43b895d56dff8d19d8" + integrity sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg== + dependencies: + decamelize "^1.1.0" + map-obj "^1.0.0" + +decamelize@^1.1.0, decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== + +deep-equal@^2.0.5: + version "2.2.0" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.0.tgz#5caeace9c781028b9ff459f33b779346637c43e6" + integrity sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw== + dependencies: + call-bind "^1.0.2" + es-get-iterator "^1.1.2" + get-intrinsic "^1.1.3" + is-arguments "^1.1.1" + is-array-buffer "^3.0.1" + is-date-object "^1.0.5" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + isarray "^2.0.5" + object-is "^1.1.5" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.4.3" + side-channel "^1.0.4" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.1" + which-typed-array "^1.1.9" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deepmerge@^4.2.2, deepmerge@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +default-gateway@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71" + integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg== + dependencies: + execa "^5.0.0" + +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + +define-properties@^1.1.3, define-properties@^1.1.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" + integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== + dependencies: + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +del@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4" + integrity sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ== + dependencies: + "@types/glob" "^7.1.1" + globby "^6.1.0" + is-path-cwd "^2.0.0" + is-path-in-cwd "^2.0.0" + p-map "^2.0.0" + pify "^4.0.1" + rimraf "^2.6.3" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== + +depd@2.0.0, depd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== + +des.js@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" + integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +detect-node@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + +diff-sequences@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" + integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + integrity sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg== + +dns-packet@^5.2.2: + version "5.5.0" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.5.0.tgz#f59cbf3396c130957c56a6ad5fd3959ccdc30065" + integrity sha512-USawdAUzRkV6xrqTjiAEp6M9YagZEzWcSUaZTcIFAiyQWW1SoI6KyId8y2+/71wbgHKQAKd+iupLv4YvEwYWvA== + dependencies: + "@leichtgewicht/ip-codec" "^2.0.1" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dom-accessibility-api@^0.5.6, dom-accessibility-api@^0.5.9: + version "0.5.16" + resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz#5a7429e6066eb3664d911e33fb0e45de8eb08453" + integrity sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg== + +dom-converter@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" + integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== + dependencies: + utila "~0.4" + +dom-serializer@^1.0.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30" + integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.2.0" + entities "^2.0.0" + +dom-serializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" + integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + entities "^4.2.0" + +dom-walk@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" + integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== + +domelementtype@^2.0.1, domelementtype@^2.2.0, domelementtype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" + integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== + +domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" + integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== + dependencies: + domelementtype "^2.2.0" + +domhandler@^5.0.2, domhandler@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" + integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== + dependencies: + domelementtype "^2.3.0" + +domutils@^2.5.2, domutils@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" + integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + +domutils@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e" + integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA== + dependencies: + dom-serializer "^2.0.0" + domelementtype "^2.3.0" + domhandler "^5.0.3" + +dot-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +electron-to-chromium@^1.4.284: + version "1.4.366" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.366.tgz#48d400f9c4af8e80f7bbad0d18730c165d43155e" + integrity sha512-XjC4pyf1no8kJe24nUfyexpWwiGRbZWXU/KbprSEvXcTXUlr3Zr5vK3lQt2to0ttpMhAc3iENccwPSKbnEW2Fg== + +electron-to-chromium@^1.4.431: + version "1.4.466" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.466.tgz#17193d70f203da3d52a89c653b8d89f47a51d79d" + integrity sha512-TSkRvbXRXD8BwhcGlZXDsbI2lRoP8dvqR7LQnqQNk9KxXBc4tG8O+rTuXgTyIpEdiqSGKEBSqrxdqEntnjNncA== + +elliptic@^6.5.3: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +encoding@^0.1.12, encoding@^0.1.13: + version "0.1.13" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" + integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== + dependencies: + iconv-lite "^0.6.2" + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enhanced-resolve@^5.0.0, enhanced-resolve@^5.7.0: + version "5.12.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz#300e1c90228f5b570c4d35babf263f6da7155634" + integrity sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +enhanced-resolve@^5.15.0: + version "5.15.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" + integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + +entities@^4.2.0, entities@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + +env-paths@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== + +envinfo@^7.7.3: + version "7.8.1" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" + integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== + +err-code@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" + integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.19.0, es-abstract@^1.20.4: + version "1.21.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.2.tgz#a56b9695322c8a185dc25975aa3b8ec31d0e7eff" + integrity sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg== + dependencies: + array-buffer-byte-length "^1.0.0" + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-set-tostringtag "^2.0.1" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.5" + get-intrinsic "^1.2.0" + get-symbol-description "^1.0.0" + globalthis "^1.0.3" + gopd "^1.0.1" + has "^1.0.3" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" + is-callable "^1.2.7" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-typed-array "^1.1.10" + is-weakref "^1.0.2" + object-inspect "^1.12.3" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.4.3" + safe-regex-test "^1.0.0" + string.prototype.trim "^1.2.7" + string.prototype.trimend "^1.0.6" + string.prototype.trimstart "^1.0.6" + typed-array-length "^1.0.4" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.9" + +es-get-iterator@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6" + integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + has-symbols "^1.0.3" + is-arguments "^1.1.1" + is-map "^2.0.2" + is-set "^2.0.2" + is-string "^1.0.7" + isarray "^2.0.5" + stop-iteration-iterator "^1.0.0" + +es-module-lexer@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.2.1.tgz#ba303831f63e6a394983fde2f97ad77b22324527" + integrity sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg== + +es-set-tostringtag@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" + integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== + dependencies: + get-intrinsic "^1.1.3" + has "^1.0.3" + has-tostringtag "^1.0.0" + +es-shim-unscopables@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" + integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== + dependencies: + has "^1.0.3" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +es6-object-assign@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c" + integrity sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw== + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-config-prettier@^8.8.0: + version "8.8.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz#bfda738d412adc917fd7b038857110efe98c9348" + integrity sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA== + +eslint-config-react-app@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz#73ba3929978001c5c86274c017ea57eb5fa644b4" + 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" + +eslint-config-react@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/eslint-config-react/-/eslint-config-react-1.1.7.tgz#a0918d0fc47d0e9bd161a47308021da85d2585b3" + integrity sha512-P4Z6u68wf0BvIvZNu+U8uQsk3DcZ1CcCI1XpUkJlG6vOa+iVcSQLgE01f2DB2kXlKRcT8/3dsH+wveLgvEgbkQ== + +eslint-import-resolver-node@^0.3.7: + version "0.3.7" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz#83b375187d412324a1963d84fa664377a23eb4d7" + integrity sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA== + dependencies: + debug "^3.2.7" + is-core-module "^2.11.0" + resolve "^1.22.1" + +eslint-module-utils@^2.7.4: + version "2.8.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz#e439fee65fc33f6bba630ff621efc38ec0375c49" + integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== + dependencies: + debug "^3.2.7" + +eslint-plugin-flowtype@^8.0.3: + version "8.0.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz#e1557e37118f24734aa3122e7536a038d34a4912" + integrity sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ== + dependencies: + lodash "^4.17.21" + string-natural-compare "^3.0.1" + +eslint-plugin-import@^2.25.3, eslint-plugin-import@^2.27.5: + version "2.27.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz#876a6d03f52608a3e5bb439c2550588e51dd6c65" + integrity sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow== + dependencies: + array-includes "^3.1.6" + array.prototype.flat "^1.3.1" + array.prototype.flatmap "^1.3.1" + debug "^3.2.7" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.7" + eslint-module-utils "^2.7.4" + has "^1.0.3" + is-core-module "^2.11.0" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.values "^1.1.6" + resolve "^1.22.1" + semver "^6.3.0" + tsconfig-paths "^3.14.1" + +eslint-plugin-jest@^25.3.0: + version "25.7.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz#ff4ac97520b53a96187bad9c9814e7d00de09a6a" + integrity sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ== + dependencies: + "@typescript-eslint/experimental-utils" "^5.0.0" + +eslint-plugin-jsx-a11y@^6.5.1, eslint-plugin-jsx-a11y@^6.7.1: + version "6.7.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz#fca5e02d115f48c9a597a6894d5bcec2f7a76976" + 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" + +eslint-plugin-prefer-arrow@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.3.tgz#e7fbb3fa4cd84ff1015b9c51ad86550e55041041" + integrity sha512-J9I5PKCOJretVuiZRGvPQxCbllxGAV/viI20JO3LYblAodofBxyMnZAJ+WGeClHgANnSJberTNoFWWjrWKBuXQ== + +eslint-plugin-react-hooks@^4.3.0, eslint-plugin-react-hooks@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" + integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== + +eslint-plugin-react@^7.27.1, eslint-plugin-react@^7.32.2: + version "7.32.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz#e71f21c7c265ebce01bcbc9d0955170c55571f10" + integrity sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg== + dependencies: + array-includes "^3.1.6" + array.prototype.flatmap "^1.3.1" + array.prototype.tosorted "^1.1.1" + doctrine "^2.1.0" + estraverse "^5.3.0" + jsx-ast-utils "^2.4.1 || ^3.0.0" + minimatch "^3.1.2" + object.entries "^1.1.6" + object.fromentries "^2.0.6" + object.hasown "^1.1.2" + object.values "^1.1.6" + prop-types "^15.8.1" + resolve "^2.0.0-next.4" + semver "^6.3.0" + string.prototype.matchall "^4.0.8" + +eslint-plugin-testing-library@^5.0.1: + version "5.10.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.10.3.tgz#e613fbaf9a145e9eef115d080b32cb488fae622e" + integrity sha512-0yhsKFsjHLud5PM+f2dWr9K3rqYzMy4cSHs3lcmFYMa1CdSzRvHGgXvsFarBjZ41gU8jhTdMIkg8jHLxGJqLqw== + dependencies: + "@typescript-eslint/utils" "^5.58.0" + +eslint-scope@5.1.1, eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-scope@^7.2.0: + version "7.2.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.1.tgz#936821d3462675f25a18ac5fd88a67cc15b393bd" + integrity sha512-CvefSOsDdaYYvxChovdrPo/ZGt8d5lrJWleAc1diXRKhHGiTYEI26cvo8Kle/wGnsizoCJjK73FMg1/IkIwiNA== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint-visitor-keys@^3.3.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz#c7f0f956124ce677047ddbc192a68f999454dedc" + integrity sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ== + +eslint-visitor-keys@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz#c22c48f48942d08ca824cc526211ae400478a994" + integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA== + +eslint-webpack-plugin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/eslint-webpack-plugin/-/eslint-webpack-plugin-4.0.1.tgz#f0f0e9afff2801d8bd41eac88e5409821ecbaccb" + integrity sha512-fUFcXpui/FftGx3NzvWgLZXlLbu+m74sUxGEgxgoxYcUtkIQbS6SdNNZkS99m5ycb23TfoNYrDpp1k/CK5j6Hw== + dependencies: + "@types/eslint" "^8.37.0" + jest-worker "^29.5.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + schema-utils "^4.0.0" + +eslint@^8.45.0: + version "8.45.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.45.0.tgz#bab660f90d18e1364352c0a6b7c6db8edb458b78" + 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" + +espree@^9.6.0: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" + integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + 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" + +execa@^7.0.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-7.1.1.tgz#3eb3c83d239488e7b409d48e8813b76bb55c9c43" + integrity sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.1" + human-signals "^4.3.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^3.0.7" + strip-final-newline "^3.0.0" + +expect@^29.0.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.5.0.tgz#68c0509156cb2a0adb8865d413b137eeaae682f7" + integrity sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg== + dependencies: + "@jest/expect-utils" "^29.5.0" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.5.0" + jest-message-util "^29.5.0" + jest-util "^29.5.0" + +express@^4.17.3: + version "4.18.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" + 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" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.11, fast-glob@^3.2.9: + version "3.2.12" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" + integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== + 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" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastest-levenshtein@^1.0.12: + version "1.0.16" + resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" + integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== + +fastq@^1.6.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + dependencies: + reusify "^1.0.4" + +faye-websocket@^0.11.3: + version "0.11.4" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" + integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== + dependencies: + websocket-driver ">=0.5.1" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +file-loader@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d" + integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw== + dependencies: + loader-utils "^2.0.0" + schema-utils "^3.0.0" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + 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" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.7" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + +follow-redirects@^1.0.0: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +fork-ts-checker-webpack-plugin@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-8.0.0.tgz#dae45dfe7298aa5d553e2580096ced79b6179504" + integrity sha512-mX3qW3idpueT2klaQXBzrIM/pHw+T0B/V9KHEvNrqijTq9NFnMZU6oreVxDYcf33P8a5cW+67PjodNHthGnNVg== + dependencies: + "@babel/code-frame" "^7.16.7" + chalk "^4.1.2" + chokidar "^3.5.3" + cosmiconfig "^7.0.1" + deepmerge "^4.2.2" + fs-extra "^10.0.0" + memfs "^3.4.1" + minimatch "^3.0.4" + node-abort-controller "^3.0.1" + schema-utils "^3.1.1" + semver "^7.3.5" + tapable "^2.2.1" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +fs-extra@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" + integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-minipass@^2.0.0, fs-minipass@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + +fs-monkey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" + integrity sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +function.prototype.name@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" + integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + functions-have-names "^1.2.2" + +functions-have-names@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +gauge@^4.0.3: + version "4.0.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.4.tgz#52ff0652f2bbf607a989793d53b751bef2328dce" + integrity sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg== + 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" + +gaze@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" + integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g== + dependencies: + globule "^1.0.0" + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f" + integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.3" + +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + integrity sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw== + +get-stream@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +get-stream@^6.0.0, get-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.1, glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@^7.0.0, glob@^7.0.3, glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + 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" + +glob@^8.0.1: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + +glob@~7.1.1: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + 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" + +global@^4.3.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" + integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== + dependencies: + min-document "^2.19.0" + process "^0.11.10" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.19.0: + version "13.20.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" + integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + dependencies: + type-fest "^0.20.2" + +globalthis@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" + integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + dependencies: + define-properties "^1.1.3" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + 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" + +globby@^13.1.1: + version "13.1.4" + resolved "https://registry.yarnpkg.com/globby/-/globby-13.1.4.tgz#2f91c116066bcec152465ba36e5caa4a13c01317" + integrity sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g== + dependencies: + dir-glob "^3.0.1" + fast-glob "^3.2.11" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^4.0.0" + +globby@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + integrity sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw== + dependencies: + array-union "^1.0.1" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +globule@^1.0.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/globule/-/globule-1.3.4.tgz#7c11c43056055a75a6e68294453c17f2796170fb" + integrity sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg== + dependencies: + glob "~7.1.1" + lodash "^4.17.21" + minimatch "~3.0.2" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +grapheme-splitter@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" + integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +handle-thing@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" + integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== + +hard-rejection@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" + integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== + +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" + integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + dependencies: + get-intrinsic "^1.1.1" + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has-unicode@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +he@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + +hosted-git-info@^2.1.4: + version "2.8.9" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== + +hosted-git-info@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224" + integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA== + dependencies: + lru-cache "^6.0.0" + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ== + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +html-entities@^2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46" + integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA== + +html-minifier-terser@^6.0.2: + version "6.1.0" + resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#bfc818934cc07918f6b3669f5774ecdfd48f32ab" + 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" + +html-webpack-plugin@^5.5.3: + version "5.5.3" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz#72270f4a78e222b5825b296e5e3e1328ad525a3e" + 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" + +htmlparser2@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" + integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.0.0" + domutils "^2.5.2" + entities "^2.0.0" + +http-cache-semantics@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" + integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw== + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + 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" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-parser-js@>=0.5.1: + version "0.5.8" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.8.tgz#af23090d9ac4e24573de6f6aecc9d84a48bf20e3" + integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== + +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + +http-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" + integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w== + dependencies: + "@tootallnate/once" "2" + agent-base "6" + debug "4" + +http-proxy-middleware@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz#e1a4dd6979572c7ab5a4e4b55095d1f32a74963f" + 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" + +http-proxy@^1.18.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg== + +https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + +human-signals@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +human-signals@^4.3.0: + version "4.3.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" + integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== + +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== + dependencies: + ms "^2.0.0" + +husky@^8.0.3: + version "8.0.3" + resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184" + integrity sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg== + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.6.2: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +icss-utils@^5.0.0, icss-utils@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" + integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== + +ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ignore@^5.1.4, ignore@^5.2.0, ignore@^5.2.4: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + +immer@^9.0.21: + version "9.0.21" + resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.21.tgz#1e025ea31a40f24fb064f1fef23e931496330176" + integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA== + +immutable@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.0.tgz#eb1738f14ffb39fd068b1dbe1296117484dd34be" + integrity sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg== + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +infer-owner@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" + integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3, inherits@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== + +internal-slot@^1.0.3, internal-slot@^1.0.4, internal-slot@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" + integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== + dependencies: + get-intrinsic "^1.2.0" + has "^1.0.3" + side-channel "^1.0.4" + +interpret@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4" + integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ== + +ip@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" + integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +ipaddr.js@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0" + integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== + +is-arguments@^1.0.4, is-arguments@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + is-typed-array "^1.1.10" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.11.0, is-core-module@^2.5.0, is-core-module@^2.9.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.0.tgz#36ad62f6f73c8253fd6472517a12483cf03e7ec4" + integrity sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ== + dependencies: + has "^1.0.3" + +is-date-object@^1.0.1, is-date-object@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-docker@^2.0.0, is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-fullwidth-code-point@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" + integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== + +is-generator-function@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-lambda@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" + integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== + +is-map@^2.0.1, is-map@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" + integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== + +is-nan@^1.2.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" + integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-cwd@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" + integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== + +is-path-in-cwd@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb" + integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ== + dependencies: + is-path-inside "^2.1.0" + +is-path-inside@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2" + integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg== + dependencies: + path-is-inside "^1.0.2" + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg== + +is-plain-obj@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" + integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== + +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-set@^2.0.1, is-set@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" + integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== + +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.10, is-typed-array@^1.1.3, is-typed-array@^1.1.9: + version "1.1.10" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" + integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + +is-weakmap@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" + integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== + +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +is-weakset@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d" + integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + +jest-diff@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.5.0.tgz#e0d83a58eb5451dcc1fa61b1c3ee4e8f5a290d63" + integrity sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.4.3" + jest-get-type "^29.4.3" + pretty-format "^29.5.0" + +jest-get-type@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5" + integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg== + +jest-matcher-utils@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz#d957af7f8c0692c5453666705621ad4abc2c59c5" + integrity sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw== + dependencies: + chalk "^4.0.0" + jest-diff "^29.5.0" + jest-get-type "^29.4.3" + pretty-format "^29.5.0" + +jest-message-util@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.5.0.tgz#1f776cac3aca332ab8dd2e3b41625435085c900e" + integrity sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.5.0" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.5.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-util@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.5.0.tgz#24a4d3d92fc39ce90425311b23c27a6e0ef16b8f" + integrity sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ== + dependencies: + "@jest/types" "^29.5.0" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-worker@^27.4.5: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest-worker@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.5.0.tgz#bdaefb06811bd3384d93f009755014d8acb4615d" + integrity sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA== + dependencies: + "@types/node" "*" + jest-util "^29.5.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +js-base64@^2.4.9: + version "2.6.4" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4" + integrity sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== + +json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + +json5@^2.1.2, json5@^2.2.2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz#76b3e6e6cece5c69d49a5792c3d01bd1a0cdc7ea" + integrity sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw== + dependencies: + array-includes "^3.1.5" + object.assign "^4.1.3" + +jwt-decode@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-3.1.2.tgz#3fb319f3675a2df0c2895c8f5e9fa4b67b04ed59" + integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A== + +kind-of@^6.0.2, kind-of@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +language-subtag-registry@~0.3.2: + version "0.3.22" + resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d" + integrity sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w== + +language-tags@=1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.5.tgz#d321dbc4da30ba8bf3024e040fa5c14661f9193a" + integrity sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ== + dependencies: + language-subtag-registry "~0.3.2" + +launch-editor@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.6.0.tgz#4c0c1a6ac126c572bd9ff9a30da1d2cae66defd7" + integrity sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ== + dependencies: + picocolors "^1.0.0" + shell-quote "^1.7.3" + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lilconfig@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" + integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +lint-staged@^13.2.3: + version "13.2.3" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.2.3.tgz#f899aad6c093473467e9c9e316e3c2d8a28f87a7" + integrity sha512-zVVEXLuQIhr1Y7R7YAWx4TZLdvuzk7DnmrsTNL0fax6Z3jrpFcas+vKbzxhhvp6TA55m1SQuWkpzI1qbfDZbAg== + dependencies: + chalk "5.2.0" + cli-truncate "^3.1.0" + commander "^10.0.0" + debug "^4.3.4" + execa "^7.0.0" + lilconfig "2.1.0" + listr2 "^5.0.7" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-inspect "^1.12.3" + pidtree "^0.6.0" + string-argv "^0.3.1" + yaml "^2.2.2" + +listr2@^5.0.7: + version "5.0.8" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-5.0.8.tgz#a9379ffeb4bd83a68931a65fb223a11510d6ba23" + integrity sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA== + dependencies: + cli-truncate "^2.1.0" + colorette "^2.0.19" + log-update "^4.0.0" + p-map "^4.0.0" + rfdc "^1.3.0" + rxjs "^7.8.0" + through "^2.3.8" + wrap-ansi "^7.0.0" + +loader-runner@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== + +loader-utils@^2.0.0, loader-utils@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c" + integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash@^4.17.11, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-update@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" + integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== + dependencies: + ansi-escapes "^4.3.0" + cli-cursor "^3.1.0" + slice-ansi "^4.0.0" + wrap-ansi "^6.2.0" + +loose-envify@^1.1.0, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +lru-cache@^7.7.1: + version "7.18.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" + integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== + +lz-string@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" + integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ== + +make-fetch-happen@^10.0.4: + version "10.2.1" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz#f5e3835c5e9817b617f2770870d9492d28678164" + integrity sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w== + dependencies: + agentkeepalive "^4.2.1" + cacache "^16.1.0" + http-cache-semantics "^4.1.0" + http-proxy-agent "^5.0.0" + https-proxy-agent "^5.0.0" + is-lambda "^1.0.1" + lru-cache "^7.7.1" + minipass "^3.1.6" + minipass-collect "^1.0.2" + minipass-fetch "^2.0.3" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + negotiator "^0.6.3" + promise-retry "^2.0.1" + socks-proxy-agent "^7.0.0" + ssri "^9.0.0" + +make-fetch-happen@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" + integrity sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg== + 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" + +map-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + integrity sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg== + +map-obj@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" + integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +mdn-data@2.0.28: + version "2.0.28" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.28.tgz#5ec48e7bef120654539069e1ae4ddc81ca490eba" + integrity sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g== + +mdn-data@2.0.30: + version "2.0.30" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc" + integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +memfs@^3.4.1, memfs@^3.4.3: + version "3.5.0" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.5.0.tgz#9da86405fca0a539addafd37dbd452344fd1c0bd" + integrity sha512-yK6o8xVJlQerz57kvPROwTMgx5WtGwC2ZxDtOUsnGl49rHjYkfQoPNZPCKH73VdLE1BwBu/+Fx/NL8NYMUw2aA== + dependencies: + fs-monkey "^1.0.3" + +meow@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-9.0.0.tgz#cd9510bc5cac9dee7d03c73ee1f9ad959f4ea364" + integrity sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ== + 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" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +micromatch@^4.0.0, micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + integrity sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ== + dependencies: + dom-walk "^0.1.0" + +min-indent@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== + +mini-css-extract-plugin@^2.7.6: + version "2.7.6" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz#282a3d38863fddcd2e0c220aaed5b90bc156564d" + integrity sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw== + dependencies: + schema-utils "^4.0.0" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@~3.0.2: + version "3.0.8" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.8.tgz#5e6a59bd11e2ab0de1cfb843eb2d82e546c321c1" + integrity sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q== + dependencies: + brace-expansion "^1.1.7" + +minimist-options@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" + integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A== + dependencies: + arrify "^1.0.1" + is-plain-obj "^1.1.0" + kind-of "^6.0.3" + +minimist@^1.2.0, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +minipass-collect@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" + integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA== + dependencies: + minipass "^3.0.0" + +minipass-fetch@^1.3.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" + integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw== + dependencies: + minipass "^3.1.0" + minipass-sized "^1.0.3" + minizlib "^2.0.0" + optionalDependencies: + encoding "^0.1.12" + +minipass-fetch@^2.0.3: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-2.1.2.tgz#95560b50c472d81a3bc76f20ede80eaed76d8add" + integrity sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA== + dependencies: + minipass "^3.1.6" + minipass-sized "^1.0.3" + minizlib "^2.1.2" + optionalDependencies: + encoding "^0.1.13" + +minipass-flush@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" + integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== + dependencies: + minipass "^3.0.0" + +minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" + integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== + dependencies: + minipass "^3.0.0" + +minipass-sized@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" + integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== + dependencies: + minipass "^3.0.0" + +minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3, minipass@^3.1.6: + version "3.3.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" + integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== + dependencies: + yallist "^4.0.0" + +minipass@^4.0.0: + version "4.2.8" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.8.tgz#f0010f64393ecfc1d1ccb5f582bcaf45f48e1a3a" + integrity sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ== + +minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + +mkdirp@^1.0.3, mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +mri@^1.1.5: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" + integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3, ms@^2.0.0, ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multicast-dns@^7.2.5: + version "7.2.5" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.5.tgz#77eb46057f4d7adbd16d9290fa7299f6fa64cced" + integrity sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg== + dependencies: + dns-packet "^5.2.2" + thunky "^1.0.2" + +multimatch@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-4.0.0.tgz#8c3c0f6e3e8449ada0af3dd29efb491a375191b3" + integrity sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ== + dependencies: + "@types/minimatch" "^3.0.3" + array-differ "^3.0.0" + array-union "^2.1.0" + arrify "^2.0.1" + minimatch "^3.0.4" + +nan@^2.17.0: + version "2.17.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" + integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== + +nanoid@^3.3.6: + version "3.3.6" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" + integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== + +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +negotiator@0.6.3, negotiator@^0.6.2, negotiator@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + +node-abort-controller@^3.0.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz#a94377e964a9a37ac3976d848cb5c765833b8548" + integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ== + +node-forge@^1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" + integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== + +node-gyp@^8.4.1: + version "8.4.1" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-8.4.1.tgz#3d49308fc31f768180957d6b5746845fbd429937" + integrity sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w== + 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" + +node-releases@^2.0.12: + version "2.0.13" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" + integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== + +node-releases@^2.0.8: + version "2.0.10" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f" + integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w== + +node-sass@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-9.0.0.tgz#c21cd17bd9379c2d09362b3baf2cbf089bce08ed" + integrity sha512-yltEuuLrfH6M7Pq2gAj5B6Zm7m+gdZoG66wTqG6mIZV/zijq3M2OO2HswtT6oBspPyFhHDcaxWpsBm0fRNDHPg== + 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" + make-fetch-happen "^10.0.4" + meow "^9.0.0" + nan "^2.17.0" + node-gyp "^8.4.1" + sass-graph "^4.0.1" + stdout-stream "^1.4.0" + "true-case-path" "^2.2.1" + +nopt@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== + dependencies: + abbrev "1" + +normalize-package-data@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-package-data@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" + integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== + dependencies: + 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@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.0, npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +npm-run-path@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00" + integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q== + dependencies: + path-key "^4.0.0" + +npmlog@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.2.tgz#c8166017a42f2dea92d6453168dd865186a70830" + integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg== + dependencies: + are-we-there-yet "^3.0.0" + console-control-strings "^1.1.0" + gauge "^4.0.3" + set-blocking "^2.0.0" + +nth-check@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" + integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== + dependencies: + boolbase "^1.0.0" + +object-assign@^4.0.1, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.12.3, object-inspect@^1.9.0: + version "1.12.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + +object-is@^1.0.1, object-is@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.3, object.assign@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" + integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +object.entries@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.6.tgz#9737d0e5b8291edd340a3e3264bb8a3b00d5fa23" + integrity sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +object.fromentries@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.6.tgz#cdb04da08c539cffa912dcd368b886e0904bfa73" + integrity sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +object.hasown@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.2.tgz#f919e21fad4eb38a57bc6345b3afd496515c3f92" + integrity sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw== + dependencies: + define-properties "^1.1.4" + es-abstract "^1.20.4" + +object.values@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.6.tgz#4abbaa71eba47d63589d402856f908243eea9b1d" + integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +oidc-client-ts@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/oidc-client-ts/-/oidc-client-ts-2.2.4.tgz#7d86b5efe2248f3637a6f3a0ee1af86764aea125" + integrity sha512-nOZwIomju+AmXObl5Oq5PjrES/qTt8bLsENJCIydVgi9TEWk7SCkOU6X3RNkY7yfySRM1OJJvDKdREZdmnDT2g== + dependencies: + crypto-js "^4.1.1" + jwt-decode "^3.1.2" + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.0, onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + dependencies: + mimic-fn "^4.0.0" + +open@^8.0.9: + version "8.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" + 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" + +optionator@^0.9.3: + version "0.9.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" + 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" + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A== + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-map@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +p-retry@^4.5.0: + version "4.6.2" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16" + integrity sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ== + dependencies: + "@types/retry" "0.12.0" + retry "^0.13.1" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +papaparse@^5.4.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-5.4.1.tgz#f45c0f871853578bd3a30f92d96fdcfb6ebea127" + integrity sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw== + +param-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" + integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-asn1@^5.0.0, parse-asn1@^5.1.5: + version "5.1.6" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" + integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== + dependencies: + asn1.js "^5.2.0" + browserify-aes "^1.0.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + +parse-json@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + 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" + +parseurl@~1.3.2, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascal-case@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" + integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pbkdf2@^3.0.3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pidtree@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" + integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw== + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +postcss-modules-extract-imports@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" + integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== + +postcss-modules-local-by-default@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz#b08eb4f083050708998ba2c6061b50c2870ca524" + integrity sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA== + dependencies: + icss-utils "^5.0.0" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.1.0" + +postcss-modules-scope@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" + integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg== + dependencies: + postcss-selector-parser "^6.0.4" + +postcss-modules-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" + integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== + dependencies: + icss-utils "^5.0.0" + +postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: + version "6.0.11" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz#2e41dc39b7ad74046e1615185185cd0b17d0c8dc" + integrity sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + +postcss@^8.4.21: + version "8.4.26" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.26.tgz#1bc62ab19f8e1e5463d98cf74af39702a00a9e94" + integrity sha512-jrXHFF8iTloAenySjM/ob3gSj7pCu0Ji49hnjqzsgSRa50hkWCKD0HQ+gMNJkW38jBI68MpAAg7ZWwHwX8NMMw== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier@^2.8.7: + version "2.8.7" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.7.tgz#bb79fc8729308549d28fe3a98fce73d2c0656450" + integrity sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw== + +pretty-error@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-4.0.0.tgz#90a703f46dd7234adb46d0f84823e9d1cb8f10d6" + integrity sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw== + dependencies: + lodash "^4.17.20" + renderkid "^3.0.0" + +pretty-format@^27.0.2: + version "27.5.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" + integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== + dependencies: + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + +pretty-format@^29.0.0, pretty-format@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.5.0.tgz#283134e74f70e2e3e7229336de0e4fce94ccde5a" + integrity sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw== + dependencies: + "@jest/schemas" "^29.4.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +pretty-quick@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/pretty-quick/-/pretty-quick-3.1.3.tgz#15281108c0ddf446675157ca40240099157b638e" + integrity sha512-kOCi2FJabvuh1as9enxYmrnBC6tVMoVOenMaBqRfsvBHB0cbpYHjdQEpSglpASDFEXVwplpcGR4CLEaisYAFcA== + dependencies: + chalk "^3.0.0" + execa "^4.0.0" + find-up "^4.1.0" + ignore "^5.1.4" + mri "^1.1.5" + multimatch "^4.0.0" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g== + +promise-retry@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" + integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== + dependencies: + err-code "^2.0.2" + retry "^0.12.0" + +prop-types@^15.5.0, prop-types@^15.6.1, prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== + +punycode@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + +qs@^6.11.0: + version "6.11.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" + integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== + dependencies: + side-channel "^1.0.4" + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +quick-lru@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" + integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@^1.2.1, range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" + 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" + +react-async-script@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/react-async-script/-/react-async-script-1.2.0.tgz#ab9412a26f0b83f5e2e00de1d2befc9400834b21" + integrity sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q== + dependencies: + hoist-non-react-statics "^3.3.0" + prop-types "^15.5.0" + +react-copy-to-clipboard@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz#09aae5ec4c62750ccb2e6421a58725eabc41255c" + integrity sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A== + dependencies: + copy-to-clipboard "^3.3.1" + prop-types "^15.8.1" + +react-dom@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" + integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.0" + +react-google-recaptcha@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/react-google-recaptcha/-/react-google-recaptcha-3.1.0.tgz#44aaab834495d922b9d93d7d7a7fb2326315b4ab" + integrity sha512-cYW2/DWas8nEKZGD7SCu9BSuVz8iOcOLHChHyi7upUuVhkpkhYG/6N3KDiTQ3XAiZ2UAZkfvYKMfAHOzBOcGEg== + dependencies: + prop-types "^15.5.0" + react-async-script "^1.2.0" + +react-hot-loader@^4.13.1: + version "4.13.1" + resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.13.1.tgz#979fd7598e27338b3faffae6ed01c65374dace5e" + integrity sha512-ZlqCfVRqDJmMXTulUGic4lN7Ic1SXgHAFw7y/Jb7t25GBgTR0fYAJ8uY4mrpxjRyWGWmqw77qJQGnYbzCvBU7g== + dependencies: + fast-levenshtein "^2.0.6" + global "^4.3.0" + hoist-non-react-statics "^3.3.0" + loader-utils "^2.0.3" + prop-types "^15.6.1" + react-lifecycles-compat "^3.0.4" + shallowequal "^1.1.0" + source-map "^0.7.3" + +react-is@^16.13.1, react-is@^16.7.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + +react-lifecycles-compat@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + +react-redux@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.1.1.tgz#8e740f3fd864a4cd0de5ba9cdc8ad39cc9e7c81a" + integrity sha512-5W0QaKtEhj+3bC0Nj0NkqkhIv8gLADH/2kYFMTHxCVqQILiWzLv6MaLuV5wJU3BQEdHKzTfcvPN0WMS6SC1oyA== + dependencies: + "@babel/runtime" "^7.12.1" + "@types/hoist-non-react-statics" "^3.3.1" + "@types/use-sync-external-store" "^0.0.3" + hoist-non-react-statics "^3.3.2" + react-is "^18.0.0" + use-sync-external-store "^1.0.0" + +react-router-dom@^6.14.2: + version "6.14.2" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.14.2.tgz#88f520118b91aa60233bd08dbd3fdcaea3a68488" + integrity sha512-5pWX0jdKR48XFZBuJqHosX3AAHjRAzygouMTyimnBPOLdY3WjzUSKhus2FVMihUFWzeLebDgr4r8UeQFAct7Bg== + dependencies: + "@remix-run/router" "1.7.2" + react-router "6.14.2" + +react-router@6.14.2: + version "6.14.2" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.14.2.tgz#1f60994d8c369de7b8ba7a78d8f7ec23df76b300" + integrity sha512-09Zss2dE2z+T1D03IheqAFtK4UzQyX8nFPWx6jkwdYzGLXd5ie06A6ezS2fO6zJfEb/SpG6UocN2O1hfD+2urQ== + dependencies: + "@remix-run/router" "1.7.2" + +react@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" + integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== + dependencies: + loose-envify "^1.1.0" + +read-pkg-up@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" + integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== + dependencies: + find-up "^4.1.0" + read-pkg "^5.2.0" + type-fest "^0.8.1" + +read-pkg@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" + integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== + dependencies: + "@types/normalize-package-data" "^2.4.0" + normalize-package-data "^2.5.0" + parse-json "^5.0.0" + type-fest "^0.6.0" + +readable-stream@^2.0.1: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + 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" + +readable-stream@^3.0.6, readable-stream@^3.5.0, readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +rechoir@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22" + integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ== + dependencies: + resolve "^1.20.0" + +redent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" + integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== + dependencies: + indent-string "^4.0.0" + strip-indent "^3.0.0" + +redux-thunk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.2.tgz#b9d05d11994b99f7a91ea223e8b04cf0afa5ef3b" + integrity sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q== + +redux@^4.0.0, redux@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197" + integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w== + dependencies: + "@babel/runtime" "^7.9.2" + +regenerate-unicode-properties@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" + integrity sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.13.11: + version "0.13.11" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== + +regenerator-transform@^0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.1.tgz#f6c4e99fc1b4591f780db2586328e4d9a9d8dc56" + integrity sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg== + dependencies: + "@babel/runtime" "^7.8.4" + +regexp.prototype.flags@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" + integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + functions-have-names "^1.2.2" + +regexpu-core@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.2.tgz#11a2b06884f3527aec3e93dbbf4a3b958a95546b" + 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" + +regjsparser@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.9.1.tgz#272d05aa10c7c1f67095b1ff0addae8442fc5709" + integrity sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ== + dependencies: + jsesc "~0.5.0" + +relateurl@^0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog== + +renderkid@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-3.0.0.tgz#5fd823e4d6951d37358ecc9a58b1f06836b6268a" + 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" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +reselect@^4.1.8: + version "4.1.8" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.8.tgz#3f5dc671ea168dccdeb3e141236f69f02eaec524" + integrity sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve@^1.10.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.1: + version "1.22.2" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" + integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== + dependencies: + is-core-module "^2.11.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resolve@^2.0.0-next.4: + version "2.0.0-next.4" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660" + integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== + +retry@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rfdc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + +rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +rxjs@^7.8.0: + version "7.8.0" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.0.tgz#90a938862a82888ff4c7359811a595e14e1e09a4" + integrity sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg== + dependencies: + tslib "^2.1.0" + +rxjs@^7.8.1: + version "7.8.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== + dependencies: + tslib "^2.1.0" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-regex-test@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" + integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + is-regex "^1.1.4" + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sass-graph@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-4.0.1.tgz#2ff8ca477224d694055bf4093f414cf6cfad1d2e" + integrity sha512-5YCfmGBmxoIRYHnKK2AKzrAkCoQ8ozO+iumT8K4tXJXRVCPf+7s1/9KxTSW3Rbvf+7Y7b4FR3mWyLnQr3PHocA== + dependencies: + glob "^7.0.0" + lodash "^4.17.11" + scss-tokenizer "^0.4.3" + yargs "^17.2.1" + +sass-loader@^13.3.2: + version "13.3.2" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-13.3.2.tgz#460022de27aec772480f03de17f5ba88fa7e18c6" + integrity sha512-CQbKl57kdEv+KDLquhC+gE3pXt74LEAzm+tzywcA0/aHZuub8wTErbjAoNI57rPUWRYRNC5WUnNl8eGJNbDdwg== + dependencies: + neo-async "^2.6.2" + +sass@^1.64.0: + version "1.64.0" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.64.0.tgz#9ca8d0acb1a704b86b7f1197dc310f568fb34638" + integrity sha512-m7YtAGmQta9uANIUJwXesAJMSncqH+3INc8kdVXs6eV6GUC8Qu2IYKQSN8PRLgiQfpca697G94klm2leYMxSHw== + dependencies: + chokidar ">=3.0.0 <4.0.0" + immutable "^4.0.0" + source-map-js ">=0.6.2 <2.0.0" + +scheduler@^0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" + integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== + dependencies: + loose-envify "^1.1.0" + +schema-utils@^3.0.0, schema-utils@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.2.tgz#36c10abca6f7577aeae136c804b0c741edeadc99" + integrity sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +schema-utils@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" + integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +schema-utils@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.1.tgz#eb2d042df8b01f4b5c276a2dfd41ba0faab72e8d" + integrity sha512-lELhBAAly9NowEsX0yZBlw9ahZG+sK/1RJ21EpzdYHKEs13Vku3LJ+MIPhh4sMs0oCCeufZQEQbMekiA4vuVIQ== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.9.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.1.0" + +scss-tokenizer@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.4.3.tgz#1058400ee7d814d71049c29923d2b25e61dc026c" + integrity sha512-raKLgf1LI5QMQnG+RxHz6oK0sL3x3I4FN2UDLqgLOGO8hodECNnNh5BXn7fAyBxrA8zVzdQizQ6XjNJQ+uBwMw== + dependencies: + js-base64 "^2.4.9" + source-map "^0.7.3" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg== + +selfsigned@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.1.1.tgz#18a7613d714c0cd3385c48af0075abf3f266af61" + integrity sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ== + dependencies: + node-forge "^1" + +"semver@2 || 3 || 4 || 5": + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8: + version "7.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.0.tgz#ed8c5dc8efb6c629c88b23d41dc9bf40c1d96cd0" + integrity sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA== + dependencies: + lru-cache "^6.0.0" + +semver@^7.5.4: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + +send@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + 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" + +serialize-javascript@^6.0.0, serialize-javascript@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c" + integrity sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w== + dependencies: + randombytes "^2.1.0" + +serve-index@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + 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" + +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shallowequal@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" + integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shell-quote@^1.7.3, shell-quote@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" + integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slash@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" + integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== + +slice-ansi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" + integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +slice-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" + integrity sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== + dependencies: + ansi-styles "^6.0.0" + is-fullwidth-code-point "^4.0.0" + +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + +snake-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c" + integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + +sockjs@^0.3.24: + version "0.3.24" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce" + integrity sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ== + dependencies: + faye-websocket "^0.11.3" + uuid "^8.3.2" + websocket-driver "^0.7.4" + +socks-proxy-agent@^6.0.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz#2687a31f9d7185e38d530bef1944fe1f1496d6ce" + integrity sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ== + dependencies: + agent-base "^6.0.2" + debug "^4.3.3" + socks "^2.6.2" + +socks-proxy-agent@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz#dc069ecf34436621acb41e3efa66ca1b5fed15b6" + integrity sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww== + dependencies: + agent-base "^6.0.2" + debug "^4.3.3" + socks "^2.6.2" + +socks@^2.6.2: + version "2.7.1" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.1.tgz#d8e651247178fde79c0663043e07240196857d55" + integrity sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ== + dependencies: + ip "^2.0.0" + smart-buffer "^4.2.0" + +"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1, source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@~0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@^0.7.3: + version "0.7.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" + integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== + +spawn-command@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2.tgz#9544e1a43ca045f8531aac1a48cb29bdae62338e" + integrity sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ== + +spdx-correct@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" + integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.13" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz#7189a474c46f8d47c7b0da4b987bb45e908bd2d5" + integrity sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w== + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + 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" + +spdy@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" + 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" + +ssri@^8.0.0, ssri@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" + integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== + dependencies: + minipass "^3.1.1" + +ssri@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-9.0.1.tgz#544d4c357a8d7b71a19700074b6883fcb4eae057" + integrity sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q== + dependencies: + minipass "^3.1.1" + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +"statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== + +stdout-stream@^1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.1.tgz#5ac174cdd5cd726104aa0c0b2bd83815d8d535de" + integrity sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA== + dependencies: + readable-stream "^2.0.1" + +stop-iteration-iterator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" + integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ== + dependencies: + internal-slot "^1.0.4" + +stream-browserify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" + integrity sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA== + dependencies: + inherits "~2.0.4" + readable-stream "^3.5.0" + +stream-http@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-3.2.0.tgz#1872dfcf24cb15752677e40e5c3f9cc1926028b5" + integrity sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.4" + readable-stream "^3.6.0" + xtend "^4.0.2" + +string-argv@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" + integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== + +string-natural-compare@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" + integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== + +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + 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" + +string-width@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +string.prototype.matchall@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz#3bf85722021816dcd1bf38bb714915887ca79fd3" + integrity sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + get-intrinsic "^1.1.3" + has-symbols "^1.0.3" + internal-slot "^1.0.3" + regexp.prototype.flags "^1.4.3" + side-channel "^1.0.4" + +string.prototype.trim@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" + integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +string.prototype.trimend@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" + integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +string.prototype.trimstart@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" + integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" + integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw== + dependencies: + ansi-regex "^6.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +style-loader@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.3.tgz#bba8daac19930169c0c9c96706749a597ae3acff" + integrity sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0, supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +svg-parser@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5" + integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ== + +svgo@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-3.0.2.tgz#5e99eeea42c68ee0dc46aa16da093838c262fe0a" + integrity sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ== + dependencies: + "@trysound/sax" "0.2.0" + commander "^7.2.0" + css-select "^5.1.0" + css-tree "^2.2.1" + csso "^5.0.5" + picocolors "^1.0.0" + +tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0, tapable@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +tar@^6.0.2, tar@^6.1.11, tar@^6.1.2: + version "6.1.13" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.13.tgz#46e22529000f612180601a6fe0680e7da508847b" + integrity sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^4.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + +terser-webpack-plugin@^5.3.7: + version "5.3.7" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz#ef760632d24991760f339fe9290deb936ad1ffc7" + integrity sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw== + 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.5" + +terser@^5.10.0, terser@^5.16.5: + version "5.16.9" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.9.tgz#7a28cb178e330c484369886f2afd623d9847495f" + integrity sha512-HPa/FdTB9XGI2H1/keLFZHxl6WNvAI4YalHGtDQTlMnJcoqSab1UwL4l1hGEhs6/GmLHBZIg/YgB++jcbzoOEg== + dependencies: + "@jridgewell/source-map" "^0.3.2" + acorn "^8.5.0" + commander "^2.20.0" + source-map-support "~0.5.20" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +through@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + +thunky@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" + integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toggle-selection@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32" + integrity sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ== + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +tree-kill@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + +trim-newlines@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" + integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== + +"true-case-path@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-2.2.1.tgz#c5bf04a5bbec3fd118be4084461b3a27c4d796bf" + integrity sha512-0z3j8R7MCjy10kc/g+qg7Ln3alJTodw9aDuVWZa3uiWqfuBMKeAeP2ocWcxoyM3D73yz3Jt/Pu4qPr4wHSdB/Q== + +ts-api-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.1.tgz#8144e811d44c749cd65b2da305a032510774452d" + integrity sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A== + +ts-loader@^9.4.4: + version "9.4.4" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.4.4.tgz#6ceaf4d58dcc6979f84125335904920884b7cee4" + integrity sha512-MLukxDHBl8OJ5Dk3y69IsKVFRA/6MwzEqBgh+OXMPB/OD01KQuWPFd1WAQP8a5PeSCAxfnkhiuWqfmFJzJQt9w== + dependencies: + chalk "^4.1.0" + enhanced-resolve "^5.0.0" + micromatch "^4.0.0" + semver "^7.3.4" + +tsconfig-paths-webpack-plugin@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.1.0.tgz#3c6892c5e7319c146eee1e7302ed9e6f2be4f763" + integrity sha512-xWFISjviPydmtmgeUAuXp4N1fky+VCtfhOkDUFIv5ea7p4wuTomI4QTrXvFBX2S4jZsmyTSrStQl+E+4w+RzxA== + dependencies: + chalk "^4.1.0" + enhanced-resolve "^5.7.0" + tsconfig-paths "^4.1.2" + +tsconfig-paths@^3.14.1: + version "3.14.2" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088" + integrity sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tsconfig-paths@^4.1.2: + version "4.2.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c" + integrity sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg== + dependencies: + json5 "^2.2.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^2.0.3, tslib@^2.1.0, tslib@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" + integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.18.0: + version "0.18.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" + integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" + integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typed-array-length@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" + integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + is-typed-array "^1.1.9" + +typescript@^5.1.6: + version "5.1.6" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274" + integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== + +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + 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" + +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz#cb5fffdcd16a05124f5a4b0bf7c3770208acbbe0" + integrity sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" + integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== + +unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + +unique-filename@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-2.0.1.tgz#e785f8675a9a7589e0ac77e0b5c34d2eaeac6da2" + integrity sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A== + dependencies: + unique-slug "^3.0.0" + +unique-slug@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" + integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== + dependencies: + imurmurhash "^0.1.4" + +unique-slug@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-3.0.0.tgz#6d347cf57c8a7a7a6044aabd0e2d74e4d76dc7c9" + integrity sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w== + dependencies: + imurmurhash "^0.1.4" + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +update-browserslist-db@^1.0.10, update-browserslist-db@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" + integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +url@^0.11.1: + version "0.11.1" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.1.tgz#26f90f615427eca1b9f4d6a28288c147e2302a32" + integrity sha512-rWS3H04/+mzzJkv0eZ7vEDGiQbgquI1fGfOad6zKvgYQi1SzMmhl7c/DdRGxhaWrVH6z0qWITo8rpnxK/RfEhA== + dependencies: + punycode "^1.4.1" + qs "^6.11.0" + +use-sync-external-store@^1.0.0, use-sync-external-store@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" + integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== + +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +util@^0.12.0: + version "0.12.5" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" + integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + which-typed-array "^1.1.2" + +utila@~0.4: + version "0.4.0" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" + integrity sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +watchpack@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" + integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + +webpack-cli@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.4.tgz#c8e046ba7eaae4911d7e71e2b25b776fcc35759b" + integrity sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg== + dependencies: + "@discoveryjs/json-ext" "^0.5.0" + "@webpack-cli/configtest" "^2.1.1" + "@webpack-cli/info" "^2.0.2" + "@webpack-cli/serve" "^2.0.5" + colorette "^2.0.14" + commander "^10.0.1" + cross-spawn "^7.0.3" + envinfo "^7.7.3" + fastest-levenshtein "^1.0.12" + import-local "^3.0.2" + interpret "^3.1.1" + rechoir "^0.8.0" + webpack-merge "^5.7.3" + +webpack-dev-middleware@^5.3.1: + version "5.3.3" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz#efae67c2793908e7311f1d9b06f2a08dcc97e51f" + 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" + +webpack-dev-server@^4.15.1: + version "4.15.1" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz#8944b29c12760b3a45bdaa70799b17cb91b03df7" + 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" + +webpack-merge@^5.7.3: + version "5.8.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61" + integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q== + dependencies: + clone-deep "^4.0.1" + wildcard "^2.0.0" + +webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack@^5.88.2: + version "5.88.2" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.88.2.tgz#f62b4b842f1c6ff580f3fcb2ed4f0b579f4c210e" + integrity sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ== + 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" + +websocket-driver@>=0.5.1, websocket-driver@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + 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" + +which-collection@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" + integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== + dependencies: + is-map "^2.0.1" + is-set "^2.0.1" + is-weakmap "^2.0.1" + is-weakset "^2.0.1" + +which-typed-array@^1.1.2, which-typed-array@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" + integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + is-typed-array "^1.1.10" + +which@^2.0.1, which@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== + dependencies: + string-width "^1.0.2 || 2 || 3 || 4" + +wildcard@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" + integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@^8.13.0: + version "8.13.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" + integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== + +xtend@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yaml@^1.10.0: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +yaml@^2.2.2: + version "2.3.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b" + integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ== + +yargs-parser@^20.2.3: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.2.1: + version "17.7.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.1.tgz#34a77645201d1a8fc5213ace787c220eabbd0967" + integrity sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw== + 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" + +yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + 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" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==