diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 40aafbec340..a786c231563 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,12 +1,8 @@ # Lines starting with '#' are comments. # Each line is a file pattern followed by one or more owners. -* @MetaMask/mobile-devs - # Design System Team app/component-library/ @MetaMask/design-system-engineers -# Allows the design system and mobile platform team to review and approve all snapshot changes. This allows for system wide design token changes to color, typography, etc. -**/*.snap @MetaMask/design-system-engineers @MetaMask/mobile-platform # Platform Team .github/CODEOWNERS @MetaMask/mobile-platform @@ -34,6 +30,7 @@ app/core/Engine/index.ts @MetaMask/mobile-pla app/core/Engine/README.md @MetaMask/mobile-platform app/core/Engine/types.ts @MetaMask/mobile-platform app/core/Engine/controllers/remote-feature-flag-controller/ @MetaMask/mobile-platform +app/core/DeeplinkManager @MetaMask/mobile-platform # Platform & Snaps Code Fencing File metro.transform.js @MetaMask/mobile-platform @MetaMask/snaps-devs @@ -44,6 +41,7 @@ app/reducers/fiatOrders/ @MetaMask/ramp # Confirmation Team app/components/Views/confirmations @MetaMask/confirmations +app/core/Engine/controllers/gas-fee-controller @MetaMask/confirmations app/core/Engine/controllers/transaction-controller @MetaMask/confirmations app/core/Analytics/events/confirmations @MetaMask/confirmations ppom @MetaMask/confirmations @@ -54,7 +52,6 @@ app/components/Approvals/WalletConnectApproval @MetaMask/sdk-devs app/components/Views/SDK @MetaMask/sdk-devs app/components/Views/WalletConnectSessions @MetaMask/sdk-devs app/core/BackgroundBridge/WalletConnectPort.ts @MetaMask/sdk-devs -app/core/DeeplinkManager @MetaMask/sdk-devs app/core/RPCMethods/RPCMethodMiddleware.ts @MetaMask/sdk-devs app/core/SDKConnect @MetaMask/sdk-devs app/core/WalletConnect @MetaMask/sdk-devs @@ -166,3 +163,9 @@ app/reducers/settings @MetaMask/wallet-ux # Transactions Team app/components/Views/transactions @MetaMask/transactions + +# Snapshots – no code owners assigned +# This allows anyone with write access to approve changes to any *.snap files. +# ⚠️ Note: Leaving this rule unassigned disables Code Owner review enforcement for snapshot files. +# ⚠️ Important: This rule must remain at the bottom of the CODEOWNERS file to take precedence over more specific path-based rules. +**/*.snap diff --git a/.github/scripts/bitrise/bitrise-results-check.ts b/.github/scripts/bitrise/bitrise-results-check.ts index b781f77cc09..0fbe2a98951 100644 --- a/.github/scripts/bitrise/bitrise-results-check.ts +++ b/.github/scripts/bitrise/bitrise-results-check.ts @@ -9,9 +9,6 @@ async function main(): Promise { console.log(`Workflow triggered actor : ${process.env.GITHUB_ACTOR}`); console.log(`Workflow triggered by: ${context.eventName}`); - // Get the commit hash from the GitHub context - const recentCommits = await getRecentCommits(); - console.log(`Recent commits: ${recentCommits}`); // Determine the E2E run flags const flags = await determineE2ERunFlags(); @@ -39,6 +36,10 @@ async function main(): Promise { // Consume the label await removeLabel("bitrise-result-ready"); + // Get the commit hash from the GitHub context + const recentCommits = await getRecentCommits(); + console.log(`Recent commits: ${recentCommits}`); + // If the E2E tests should run, check the Bitrise test status if (shouldRun) { diff --git a/.github/workflows/changelog-check.yml b/.github/workflows/changelog-check.yml new file mode 100644 index 00000000000..d6d13c7af4d --- /dev/null +++ b/.github/workflows/changelog-check.yml @@ -0,0 +1,18 @@ +name: ChangeLog Check + +on: + pull_request: + types: [opened, synchronize, labeled, unlabeled] + +jobs: + check-changelog: + uses: MetaMask/github-tools/.github/workflows/changelog-check.yml@fd5f71cd6cb3c64e4fab7db56ce6b53c75732f95 + with: + base-branch: ${{ github.event.pull_request.base.ref }} + head-ref: ${{ github.head_ref }} + labels: ${{ toJSON(github.event.pull_request.labels) }} + repo: ${{ github.repository }} + secrets: + gh-token: ${{ secrets.PR_TOKEN }} + + diff --git a/.github/workflows/crowdin-branch-cleanup.yml b/.github/workflows/crowdin-branch-cleanup.yml deleted file mode 100644 index c58b23bcf82..00000000000 --- a/.github/workflows/crowdin-branch-cleanup.yml +++ /dev/null @@ -1,78 +0,0 @@ -name: Crowdin - Branch and Label Cleanup for merged localization PR -# This action should delete the branch from Crowdin after the localization PR is -# merged to the original branch. It should also remove the "ready-for-translation" label - -# TODO: Add trigger for merge of localization PR. -on: workflow_dispatch - -jobs: - prestep: - runs-on: ubuntu-latest - outputs: - branch: ${{ steps.extract_current_branch.outputs.branch }} - pr: ${{ steps.get-prs.outputs.pr }} - modified_branch_name: ${{ steps.extract_modified_branch_name.outputs.modified_branch_name }} - steps: - - name: Extract current branch name - shell: bash - run: | - echo "running on branch ${GITHUB_REF##*/}" - echo "other version: ${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" - echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> "$GITHUB_OUTPUT" - id: extract_current_branch - - - name: Get PR with Label for this branch - id: get-prs - run: | - LABEL="ready-for-translation" - API_URL="https://api.github.com/repos/Metamask/crowdin-sandbox/pulls?head:${{steps.extract_current_branch.outputs.branch}}&state=open&per_page=100" - # Fetch the list of open pull requests with the specified label using curl - PRS=$(curl -sS --header "Authorization: Bearer $GITHUB_TOKEN" "$API_URL") - PR=$(echo "$PRS" | jq -r '.[] | select(.labels[].name == "'"$LABEL"'") | .number | @json') - echo "Found PR: $PR" - echo "pr=$PR" >> "$GITHUB_OUTPUT" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CURRENT_BRANCH: ${{ steps.extract_current_branch.outputs.branch }} - - - name: Modified branch name - run: echo "modified_branch_name="${{ steps.extract_current_branch.outputs.branch }} | sed 's#/#-#g'"" >> "$GITHUB_OUTPUT" - id: extract_modified_branch_name - - github_cleanup: - runs-on: ubuntu-latest - needs: prestep - steps: - - name: Remove label from PR - uses: actions/github-script@v7 - if: needs.prestep.outputs.pr != null || needs.prestep.outputs.pr != '' - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const label = "ready-for-translation"; - await github.issues.removeLabel({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: ${{ needs.prestep.outputs.pr }}, - name: label - }); - - crowdin_cleanup: - runs-on: ubuntu-latest - needs: prestep - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} - CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - ref: ${{ needs.prestep.outputs.branch }} - - - name: Delete branch within Crowdin - if: needs.prestep.outputs.branch != 'main' - uses: crowdin/github-action@c953b17499daa6be3e5afbf7a63616fb02d8b18d - with: - command: ${{ needs.prestep.outputs.modified_branch_name }} - command_args: -v diff --git a/.github/workflows/crowdin-branch-pr-ready-for-translation.yml b/.github/workflows/crowdin-branch-pr-ready-for-translation.yml deleted file mode 100644 index b703f91edff..00000000000 --- a/.github/workflows/crowdin-branch-pr-ready-for-translation.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: Crowdin - Ready for translations label added, push to crowdin - -# When an individual is working on a feature which requires translations, they can -# add a label "ready-for-translation" which will trigger this action to push the -# source and translation files to Crowdin. We will always push main as the base of -# the crowdin branch creation and then push in the changes over the top. This ensures -# that the translations which have already been done and approved previously do not -# show as needing to be translated again in the crowdin branch. - -# TODO: switch to trigger on label add once testing complete -on: workflow_dispatch - -jobs: - crowdin-upload: - runs-on: ubuntu-latest - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} - CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} - - steps: - - name: Extract current branch name - shell: bash - run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> "$GITHUB_OUTPUT" - id: extract_current_branch - - - name: Modified branch name - run: echo "modified_branch_name="${{ steps.extract_current_branch.outputs.branch }} | sed 's#/#-#g'"" >> "$GITHUB_OUTPUT" - id: extract_modified_branch_name - - - name: Checkout - uses: actions/checkout@v3 - with: - ref: main - - - name: Crowdin push main as baseline - uses: crowdin/github-action@c953b17499daa6be3e5afbf7a63616fb02d8b18d - with: - crowdin_branch_name: ${{ steps.extract_modified_branch_name.outputs.modified_branch_name }} - upload_sources: true - upload_translations_args: --import-eq-suggestions --auto-approve-imported --verbose - upload_translations: true - - - name: Checkout Branch and push to crowdin - uses: actions/checkout@v3 - with: - ref: ${{ steps.extract_current_branch.outputs.branch }} - - name: Crowdin sources push - uses: crowdin/github-action@c953b17499daa6be3e5afbf7a63616fb02d8b18d - with: - crowdin_branch_name: ${{ steps.extract_modified_branch_name.outputs.modified_branch_name }} - upload_sources: true - upload_sources_args: --auto-update --verbose - upload_translations: false diff --git a/.github/workflows/crowdin-pull-branch-pr-completed-translations.yml b/.github/workflows/crowdin-pull-branch-pr-completed-translations.yml deleted file mode 100644 index 6b47c65da04..00000000000 --- a/.github/workflows/crowdin-pull-branch-pr-completed-translations.yml +++ /dev/null @@ -1,64 +0,0 @@ -name: Crowdin - Find all branches with translations and trigger completion checks -# This workflow will run on a schedule. It will pull all pull requests with a label of -# ready-for-translation and create a matrix of the associated branches to run the -# crowdin-reusable-translation-download.yml workflow on. -# That workflow will check the status of the translations and if complete create a pull -# request with the translations off of the branch. - -permissions: - contents: write - pull-requests: write - -# TODO: Add a schedule to run this workflow twice a day(?) once the testing is complete -on: workflow_dispatch - -jobs: - run-check-and-download-for-branch: - needs: get-branches - if: ${{ needs.get-branches.outputs.matrix != '[]' && needs.get-branches.outputs.matrix != '' }} - strategy: - fail-fast: false - matrix: - branch: ${{fromJson(needs.get-branches.outputs.matrix)}} - uses: ./.github/workflows/crowdin-reusable-translation-download.yml - with: - branch: ${{ matrix.branch }} - secrets: - gh_token: ${{ secrets.GITHUB_TOKEN }} - crowdin_personal_token: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} - crowdin_project_id: ${{ secrets.CROWDIN_PROJECT_ID }} - - get-branches: - runs-on: ubuntu-latest - outputs: - matrix: ${{ steps.matrix-outputs.outputs.matrix }} - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Get Branches with Label - id: get-branches - run: | - GITHUB_TOKEN="${{ secrets.GITHUB_TOKEN }}" - REPO="${{ github.repository }}" - - LABEL="ready-for-translation" - API_URL="https://api.github.com/repos/$REPO/pulls?state=open&per_page=100" - - # Fetch the list of open pull requests with the specified label using curl - PRS=$(curl -sS --header "Authorization: Bearer $GITHUB_TOKEN" "$API_URL") - - BRANCHES=$(echo "$PRS" | jq -r '[.[] | select(.labels[].name == "'"$LABEL"'") | .head.ref] | @json') - echo "Found branches: $BRANCHES" - echo "branches=$BRANCHES" >> "$GITHUB_OUTPUT" - - - name: Set up matrix - id: matrix-outputs - run: | - # Parse the branches output and create a matrix - BRANCHES="${{ toJson(steps.get-branches.outputs.branches) }}" - echo "Creating matrix from branches..." - MATRIX="${BRANCHES}" - echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT" - - diff --git a/.github/workflows/crowdin-reusable-translation-download.yml b/.github/workflows/crowdin-reusable-translation-download.yml deleted file mode 100644 index c7562f8ad89..00000000000 --- a/.github/workflows/crowdin-reusable-translation-download.yml +++ /dev/null @@ -1,68 +0,0 @@ -name: Crowdin - Check translation progress and download if complete (unless main) -# This is a reusable workflow that is called by crowdin-pull-branch-pr-completed-translations -# across all branches which have a label of "ready-for-translation" aka being translated. -# This workflow will check the translation progress and download the translations if -# they are 100% translated. If the branch that is running this is main it will skip completion -# check and just pull whatever translations are available. - - -permissions: - contents: write - pull-requests: write - -on: - workflow_call: - inputs: - branch: - required: true - type: string - secrets: - gh_token: - required: true - crowdin_project_id: - required: true - crowdin_personal_token: - required: true - -jobs: - crowdin: - runs-on: ubuntu-latest - env: - GITHUB_TOKEN: ${{ secrets.gh_token }} - CROWDIN_PERSONAL_TOKEN: ${{ secrets.crowdin_personal_token }} - CROWDIN_PROJECT_ID: ${{ secrets.crowdin_project_id }} - - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - ref: ${{ inputs.branch }} - - - name: Modified branch name - run: echo "modified_branch_name="${{ inputs.branch }} | sed 's#/#-#g'"" >> "$GITHUB_OUTPUT" - id: extract_modified_branch_name - - - name: Check translation progress - # when main just pull whatever you have (aka skip this) - need to test - if: ${{ inputs.branch != 'main' }} - uses: crowdin/github-action@c953b17499daa6be3e5afbf7a63616fb02d8b18d - with: - command: 'status translation' - command_args: '-b ${{ steps.extract_modified_branch_name.outputs.modified_branch_name }} --fail-if-incomplete' - - - name: Synchronize with Crowdin - uses: crowdin/github-action@c953b17499daa6be3e5afbf7a63616fb02d8b18d - with: - crowdin_branch_name: ${{ steps.extract_modified_branch_name.outputs.modified_branch_name }} - upload_sources: true - upload_translations: true - download_translations: true - skip_untranslated_strings: true - export_only_approved: true - localization_branch_name: l10n_crowdin_translations_${{ inputs.branch }} - - create_pull_request: true - skip_ref_checkout: true - pull_request_title: New Crowdin translations for ${{ inputs.branch }} - pull_request_body: New Crowdin pull request with translations for ${{ inputs.branch }} - pull_request_base_branch_name: ${{ inputs.branch }} diff --git a/.github/workflows/crowdin-upload-both-sources-translations.yml b/.github/workflows/crowdin-upload-both-sources-translations.yml deleted file mode 100644 index 958344c7a55..00000000000 --- a/.github/workflows/crowdin-upload-both-sources-translations.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Crowdin - Upload Both Sources and Translations Crowdin Action -# This action is intended to ensure our main branch on crowdin is in sync with our -# main branch on github and will run on every push to main that has changes to any -# locales files. - -# TODO: Change to trigger on merge to main when locales files are changed (after testing) -# This should replace the current crowdin_action.yml file (after testing) -on: workflow_dispatch - -jobs: - crowdin-upload: - runs-on: ubuntu-latest - steps: - - name: Extract current branch name - shell: bash - run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> "$GITHUB_OUTPUT" - id: extract_current_branch - - name: Checkout - uses: actions/checkout@v3 - - - name: Crowdin push - uses: crowdin/github-action@c953b17499daa6be3e5afbf7a63616fb02d8b18d - with: - crowdin_branch_name: ${{ steps.extract_current_branch.outputs.branch }} - upload_sources: true - upload_translations: true - upload_translations_args: --import-eq-suggestions --auto-approve-imported --verbose - download_translations: false - env: - CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} - CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} diff --git a/.gitignore b/.gitignore index 7d13536c267..453c91ee2d6 100644 --- a/.gitignore +++ b/.gitignore @@ -137,3 +137,6 @@ web-build/ # CICD github-tools/ + +# API Monitor logs +api-monitor-logs/ diff --git a/.iyarc b/.iyarc index e69de29bb2d..696cadaf648 100644 --- a/.iyarc +++ b/.iyarc @@ -0,0 +1,2 @@ +# Advisory exclusions +GHSA-h9w6-f932-gq62 \ No newline at end of file diff --git a/.js.env.example b/.js.env.example index 3a581682419..1d46e7fa111 100644 --- a/.js.env.example +++ b/.js.env.example @@ -112,7 +112,6 @@ export MM_PERMISSIONS_SETTINGS_V1_ENABLED="" # Feature flag for Stablecoin Lending UI export MM_STABLECOIN_LENDING_UI_ENABLED="true" - # Activates remote feature flag override mode. # Remote feature flag values won't be updated, # and selectors should return their fallback values diff --git a/CHANGELOG.md b/CHANGELOG.md index 866039be93b..c82c8b72f9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,262 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [7.45.0] + +### Changed + +- fix(multi-srp): display errors only after all the words are have been entered ([#14607](https://github.com/MetaMask/metamask-mobile/pull/14607)) +- fix(multi-srp): display alternative text color when in dark mode([#14718](https://github.com/MetaMask/metamask-mobile/pull/14718)) + +### Added + +- feat(4213-2) update network icons ([#14069](https://github.com/MetaMask/metamask-mobile/pull/14069)) +- feat(ramp): add backpress handler to expanded quotes view ([#14210](https://github.com/MetaMask/metamask-mobile/pull/14210)) +- feat(ramp): paymentMethods refactor for sdk evolution ([#13464](https://github.com/MetaMask/metamask-mobile/pull/13464)) +- feat(ramp): erc20 gas and balance checks for off-ramp ([#12526](https://github.com/MetaMask/metamask-mobile/pull/12526)) +- feat(4213-3): network badge positioning ([#14071](https://github.com/MetaMask/metamask-mobile/pull/14071)) +- feat(4213-1): rounded square network icons ([#14065](https://github.com/MetaMask/metamask-mobile/pull/14065)) +- feat: new cicd integration changelog-check ([#14011](https://github.com/MetaMask/metamask-mobile/pull/14011)) +- feat: 14467 expo ios simulator ([#14569](https://github.com/MetaMask/metamask-mobile/pull/14569)) +- feat: Auto-failover to Quicknode when Infura is down ([#14139](https://github.com/MetaMask/metamask-mobile/pull/14139)) +- feat: bridge solana bridge button ([#14364](https://github.com/MetaMask/metamask-mobile/pull/14364)) +- feat: multi srp reveal seed ([#13825](https://github.com/MetaMask/metamask-mobile/pull/13825)) +- feat: add account syncing ([#14291](https://github.com/MetaMask/metamask-mobile/pull/14291)) +- feat: Add support for native asset token images on custom networks ([#14491](https://github.com/MetaMask/metamask-mobile/pull/14491)) +- feat: feature flag to disable epd ([#14407](https://github.com/MetaMask/metamask-mobile/pull/14407)) +- feat: api request logging ([#14083](https://github.com/MetaMask/metamask-mobile/pull/14083)) +- feat: bridge top tokens ([#14258](https://github.com/MetaMask/metamask-mobile/pull/14258)) +- feat: add `MegaETH Testnet` as default network ([#14241](https://github.com/MetaMask/metamask-mobile/pull/14241)) +- feat: add new `completedOnboarding` onboarding state property ([#14370](https://github.com/MetaMask/metamask-mobile/pull/14370)) +- feat: Init asset details balance, remove PV flag ([#14439](https://github.com/MetaMask/metamask-mobile/pull/14439)) +- feat: util file for phishing detection ([#14232](https://github.com/MetaMask/metamask-mobile/pull/14232)) +- feat: upgrade `@testing-library/react-native` to `13.2.0` ([#14450](https://github.com/MetaMask/metamask-mobile/pull/14450)) +- feat: add metrics for Alert System ([#14246](https://github.com/MetaMask/metamask-mobile/pull/14246)) +- feat: Updated design-tokens package to 7.0 ([#14395](https://github.com/MetaMask/metamask-mobile/pull/14395)) +- feat: bump `@metamask/notification-services-controller` to `^5.0.1` ([#14296](https://github.com/MetaMask/metamask-mobile/pull/14296)) +- feat: added mmpoly and mmsans font files ([#14394](https://github.com/MetaMask/metamask-mobile/pull/14394)) +- feat: Snaps UI text styling inheritance ([#14355](https://github.com/MetaMask/metamask-mobile/pull/14355)) +- feat: solana opt-in modal ([#14298](https://github.com/MetaMask/metamask-mobile/pull/14298)) +- feat: add quote details card component to Bridge UI ([#14264](https://github.com/MetaMask/metamask-mobile/pull/14264)) +- feat: add accounts to different srps ([#13852](https://github.com/MetaMask/metamask-mobile/pull/13852)) +- feat: Support input types on `SnapUIInput` ([#14312](https://github.com/MetaMask/metamask-mobile/pull/14312)) +- feat: multichain trx history ([#13922](https://github.com/MetaMask/metamask-mobile/pull/13922)) +- feat: escape / sanitize signTypedData update ([#14280](https://github.com/MetaMask/metamask-mobile/pull/14280)) +- feat: add phishing tracking events to PhishingModal component ([#14254](https://github.com/MetaMask/metamask-mobile/pull/14254)) +- feat: upgrade to brand evolution colors ([#14218](https://github.com/MetaMask/metamask-mobile/pull/14218)) + +### Fixed + +- fix(swaps): set default slippage when source or destination token is not stablecoin ([#14730](https://github.com/MetaMask/metamask-mobile/pull/14730)) +- fix: cp-7.45.0 fix block explorer link for default networks on trx detail modal. ([#14498](https://github.com/MetaMask/metamask-mobile/pull/14498)) +- fix(14255): invalid url on account list ([#14259](https://github.com/MetaMask/metamask-mobile/pull/14259)) +- fix(snaps): Update snap footer buttons ([#13953](https://github.com/MetaMask/metamask-mobile/pull/13953)) +- fix(14305): removed background color for header in QR code screen ([#14411](https://github.com/MetaMask/metamask-mobile/pull/14411)) +- fix: deeplinks when non evm network is selected ([#14521](https://github.com/MetaMask/metamask-mobile/pull/14521)) +- fix: account syncing flaky E2E tests ([#14557](https://github.com/MetaMask/metamask-mobile/pull/14557)) +- fix: show multisrp banner ([#14564](https://github.com/MetaMask/metamask-mobile/pull/14564)) +- fix: Crowdin Action ([#14562](https://github.com/MetaMask/metamask-mobile/pull/14562)) +- fix: 10371 hide biometrics button on manual lock ([#14396](https://github.com/MetaMask/metamask-mobile/pull/14396)) +- fix: temporarily disable identity E2E ([#14570](https://github.com/MetaMask/metamask-mobile/pull/14570)) +- fix: cp-7.44.0 STAKE-1005 refresh staking data when staking txs are confirmed ([#14520](https://github.com/MetaMask/metamask-mobile/pull/14520)) +- fix: SDK Connection when multichain account is selected ([#14494](https://github.com/MetaMask/metamask-mobile/pull/14494)) +- fix: activity reloads every minute ([#14465](https://github.com/MetaMask/metamask-mobile/pull/14465)) +- fix: prevent text overlap in notification opt-in modal ([#14481](https://github.com/MetaMask/metamask-mobile/pull/14481)) +- fix: cp-7.44.0 Update traits when tracked settings change 2/2 ([#14088](https://github.com/MetaMask/metamask-mobile/pull/14088)) +- fix: cp-7.44.0 Add notification when redesigned transaction confirmation submitted and finalized ([#14495](https://github.com/MetaMask/metamask-mobile/pull/14495)) +- fix: cp-7.44.0 Fix header styling for redesigned staking confirmations ([#14472](https://github.com/MetaMask/metamask-mobile/pull/14472)) +- fix: update `ConfirmAlertModal` copy blockaid ([#14206](https://github.com/MetaMask/metamask-mobile/pull/14206)) +- fix: code fence name - show only in Beta ([#14490](https://github.com/MetaMask/metamask-mobile/pull/14490)) +- fix: Prevent re-renders of Field component in Snaps UI [cp-7.44.0] ([#14475](https://github.com/MetaMask/metamask-mobile/pull/14475)) +- fix: hide show private key in non-evm accounts ([#14466](https://github.com/MetaMask/metamask-mobile/pull/14466)) +- fix: fix typo in network message ([#14434](https://github.com/MetaMask/metamask-mobile/pull/14434)) +- fix: create Solana account in beta builds ([#14460](https://github.com/MetaMask/metamask-mobile/pull/14460)) +- fix: activity showing same transactions ([#14449](https://github.com/MetaMask/metamask-mobile/pull/14449)) +- fix: Prevent Snap footer buttons from being pushed out of the modal ([#14430](https://github.com/MetaMask/metamask-mobile/pull/14430)) +- fix: Disable auto correct on Snaps UI inputs [cp-7.44.0] ([#14433](https://github.com/MetaMask/metamask-mobile/pull/14433)) +- fix: 3273 keyboard blocks send flow (Solana) ([#14403](https://github.com/MetaMask/metamask-mobile/pull/14403)) +- fix: fix dark mode for trx history network selector ([#14416](https://github.com/MetaMask/metamask-mobile/pull/14416)) +- fix: #3931 Stop loading when enabling biometrics from settings ([#14412](https://github.com/MetaMask/metamask-mobile/pull/14412)) +- fix: Remove bitcoin from beta release ([#14406](https://github.com/MetaMask/metamask-mobile/pull/14406)) +- fix: cp-7.44.0 Add new feature flag for staking confirmations ([#14401](https://github.com/MetaMask/metamask-mobile/pull/14401)) +- fix: E2E phishing test on android ([#14402](https://github.com/MetaMask/metamask-mobile/pull/14402)) +- fix: import button ([#14398](https://github.com/MetaMask/metamask-mobile/pull/14398)) +- fix: #13410: Don't switch networks when 'Close' button is tapped in Add Network flow ([#14297](https://github.com/MetaMask/metamask-mobile/pull/14297)) +- fix: clear error if the srp is cleared manually. ([#14327](https://github.com/MetaMask/metamask-mobile/pull/14327)) +- fix: small update for event consistency ([#14357](https://github.com/MetaMask/metamask-mobile/pull/14357)) +- fix: Hide account list selector balance for non evm accounts ([#14379](https://github.com/MetaMask/metamask-mobile/pull/14379)) +- fix: Dont send empty set "Token Added" event to Mixpanel ([#14303](https://github.com/MetaMask/metamask-mobile/pull/14303)) +- fix: Resolve a couple of Snaps UI dark mode issues ([#14353](https://github.com/MetaMask/metamask-mobile/pull/14353)) +- fix: anonymous props that's not moved to sensitive props ([#12931](https://github.com/MetaMask/metamask-mobile/pull/12931)) +- fix: notification switch loading flicker ([#14331](https://github.com/MetaMask/metamask-mobile/pull/14331)) +- fix: Relocate confirmations code to `legacy` folder ([#14313](https://github.com/MetaMask/metamask-mobile/pull/14313)) +- fix: ledger singing on re-designed signature pages ([#14266](https://github.com/MetaMask/metamask-mobile/pull/14266)) +- fix: adds translations for a Swap tx in the Multichain activity view ([#14314](https://github.com/MetaMask/metamask-mobile/pull/14314)) +- fix: Fix missing invalid password for login #13558 ([#14308](https://github.com/MetaMask/metamask-mobile/pull/14308)) +- fix: Remove `Transaction Finalized` event tied to STX ([#14293](https://github.com/MetaMask/metamask-mobile/pull/14293)) +- fix: yml formatting causing error ([#14277](https://github.com/MetaMask/metamask-mobile/pull/14277)) +- fix: reduce tests worker for only performance tests ([#14051](https://github.com/MetaMask/metamask-mobile/pull/14051)) +- fix: scroll for the confirmation screen ([#14269](https://github.com/MetaMask/metamask-mobile/pull/14269)) +- fix: STAKE-964: bumped @metamask/earn-controller dependency to resolve pooled-staking geo-block for fresh installs ([#14257](https://github.com/MetaMask/metamask-mobile/pull/14257)) +- fix: updates a padding style specifically for Android devices ([#14725](https://github.com/MetaMask/metamask-mobile/pull/14725)) +- fix(swaps): set default slippage when source or destination token is not stablecoin ([#14730](https://github.com/MetaMask/metamask-mobile/pull/14730)) + +## [7.44.0] + +### Added + +- feat(ramp): add backpress handler to expanded quotes view ([#14210](https://github.com/MetaMask/metamask-mobile/pull/14210)) +- feat(4213-3): network badge positioning ([#14071](https://github.com/MetaMask/metamask-mobile/pull/14071)) +- feat(4213-1): rounded square network icons ([#14065](https://github.com/MetaMask/metamask-mobile/pull/14065)) +- feat(4213-2) update network icons ([#14069](https://github.com/MetaMask/metamask-mobile/pull/14069)) +- feat(ramp): add non evm balance ([#13948](https://github.com/MetaMask/metamask-mobile/pull/13948)) +- feat: add quote info modal component ([#14263](https://github.com/MetaMask/metamask-mobile/pull/14263)) +- feat: SPL TokenList v2 ([#14126](https://github.com/MetaMask/metamask-mobile/pull/14126)) +- feat: Bridge dest token ([#14135](https://github.com/MetaMask/metamask-mobile/pull/14135)) +- feat: Adding BSC to STX Supported Chains Array (prod) ([#14230](https://github.com/MetaMask/metamask-mobile/pull/14230)) +- feat: add wallet_revokePermissions rpc call ([#14091](https://github.com/MetaMask/metamask-mobile/pull/14091)) +- feat: Add `getPreferences` hook ([#14062](https://github.com/MetaMask/metamask-mobile/pull/14062)) +- feat: Enforce 3-minute idle time for BrowserTabs before unmounting them ([#14175](https://github.com/MetaMask/metamask-mobile/pull/14175)) +- feat: Add Linea to Smart Transaction supported chains ([#14018](https://github.com/MetaMask/metamask-mobile/pull/14018)) +- feat: import srp ([#13768](https://github.com/MetaMask/metamask-mobile/pull/13768)) +- feat: add inline alert (origin mismatch) to SIWE ([#13773](https://github.com/MetaMask/metamask-mobile/pull/13773)) +- feat: Add BSC to Smart Transaction supported chains ([#13964](https://github.com/MetaMask/metamask-mobile/pull/13964)) +- feat: STAKE-902: build lending empty state component ([#14107](https://github.com/MetaMask/metamask-mobile/pull/14107)) +- feat: use new identity hooks ([#14081](https://github.com/MetaMask/metamask-mobile/pull/14081)) +- feat: add bridge slippage modal component using segmented control ([#14070](https://github.com/MetaMask/metamask-mobile/pull/14070)) +- feat: add carousel component ([#13010](https://github.com/MetaMask/metamask-mobile/pull/13010)) +- feat: STAKE-958 - added migration 070 to remove unused staking state ([#14089](https://github.com/MetaMask/metamask-mobile/pull/14089)) +- feat: Implement claim rewards confirmation ([#14049](https://github.com/MetaMask/metamask-mobile/pull/14049)) +- feat: Implement Segment sampling for expected errors ([#13874](https://github.com/MetaMask/metamask-mobile/pull/13874)) +- feat: Rename `transactionMetrics` to `confirmationMetrics` ([#14080](https://github.com/MetaMask/metamask-mobile/pull/14080)) +- feat: Add `TransactionController` metric handlers ([#14020](https://github.com/MetaMask/metamask-mobile/pull/14020)) +- feat: e2e gate ([#13696](https://github.com/MetaMask/metamask-mobile/pull/13696)) +- feat: add segmented control component ([#14066](https://github.com/MetaMask/metamask-mobile/pull/14066)) +- feat: Implement MaxBrowserTabModal at 5 browser tabs ([#14033](https://github.com/MetaMask/metamask-mobile/pull/14033)) +- feat: add button toggle component ([#14064](https://github.com/MetaMask/metamask-mobile/pull/14064)) +- feat: bridge source token selector ([#13915](https://github.com/MetaMask/metamask-mobile/pull/13915)) +- feat: add new identity hooks ([#14045](https://github.com/MetaMask/metamask-mobile/pull/14045)) +- feat: bridge tx submission ([#13577](https://github.com/MetaMask/metamask-mobile/pull/13577)) +- feat: integrate blockaid alert into the Alert System ([#13744](https://github.com/MetaMask/metamask-mobile/pull/13744)) + +### Fixed + +- fix: reduce tests worker for only performance tests ([#14051](https://github.com/MetaMask/metamask-mobile/pull/14051)) +- fix: scroll for the confirmation screen ([#14269](https://github.com/MetaMask/metamask-mobile/pull/14269)) +- fix: STAKE-964: bumped @metamask/earn-controller dependency to resolve pooled-staking geo-block for fresh installs ([#14257](https://github.com/MetaMask/metamask-mobile/pull/14257)) +- fix(snaps): Update snap footer buttons ([#13953](https://github.com/MetaMask/metamask-mobile/pull/13953)) +- fix: default open links turn true with attaching the protocol per intent filter ([#14222](https://github.com/MetaMask/metamask-mobile/pull/14222)) +- fix: waitAndTap on ad carousel banner ([#14198](https://github.com/MetaMask/metamask-mobile/pull/14198)) +- fix: bump `@metamask/keyring-controller` to `^19.2.2` ([#14229](https://github.com/MetaMask/metamask-mobile/pull/14229)) +- fix: return the same track event reference ([#14205](https://github.com/MetaMask/metamask-mobile/pull/14205)) +- fix: Fix mobile redesigned transaction metrics ([#14219](https://github.com/MetaMask/metamask-mobile/pull/14219)) +- fix: Display correct snap name when connecting ([#14204](https://github.com/MetaMask/metamask-mobile/pull/14204)) +- fix: Add staking claim event location ([#14203](https://github.com/MetaMask/metamask-mobile/pull/14203)) +- fix: ramps: change token to tap and confirm ([#14197](https://github.com/MetaMask/metamask-mobile/pull/14197)) +- fix: Fix a number of rendering problems with `AvatarFavicon` ([#14191](https://github.com/MetaMask/metamask-mobile/pull/14191)) +- fix: Disable Snaps APIs when using WalletConnect or SDK ([#14187](https://github.com/MetaMask/metamask-mobile/pull/14187)) +- fix: yarn setup bitrise ([#14174](https://github.com/MetaMask/metamask-mobile/pull/14174)) +- fix: Address final design adjustments for redesigned confirmations ([#14113](https://github.com/MetaMask/metamask-mobile/pull/14113)) +- fix: Add support for swipe navigation on android for staking confirma… ([#14125](https://github.com/MetaMask/metamask-mobile/pull/14125)) +- fix: Snap account actions ([#14013](https://github.com/MetaMask/metamask-mobile/pull/14013)) +- fix: toggle to display the correct balance ([#13916](https://github.com/MetaMask/metamask-mobile/pull/13916)) +- fix: Xcode 16 bitcode upload issue ([#14124](https://github.com/MetaMask/metamask-mobile/pull/14124)) +- fix: change function in `interfaceController.ts` to a memorised function to imporve performance ([#14090](https://github.com/MetaMask/metamask-mobile/pull/14090)) +- fix: Not report invalid URL errors to sentry ([#14115](https://github.com/MetaMask/metamask-mobile/pull/14115)) +- fix: Loading state bug ([#14096](https://github.com/MetaMask/metamask-mobile/pull/14096)) +- fix: android BottomSheet missing padding bottom ([#13993](https://github.com/MetaMask/metamask-mobile/pull/13993)) +- fix: prevent unintentional remote feature flag override ([#14086](https://github.com/MetaMask/metamask-mobile/pull/14086)) +- fix: when cancelling signature by swiping modal out it should not navigate back ([#14085](https://github.com/MetaMask/metamask-mobile/pull/14085)) +- fix: fix cannot read length property ([#14046](https://github.com/MetaMask/metamask-mobile/pull/14046)) +- fix: account name / label overflow on re-designed confirmation pages ([#14044](https://github.com/MetaMask/metamask-mobile/pull/14044)) +- fix: moved xcode 16 as default and applied xcode 15 only to testflight builds ([#14032](https://github.com/MetaMask/metamask-mobile/pull/14032)) +- fix: inherit icon size from text component parent ([#14024](https://github.com/MetaMask/metamask-mobile/pull/14024)) +- fix: animation added for loading state on SnapUILink button ([#13973](https://github.com/MetaMask/metamask-mobile/pull/13973)) +- fix: Revert "chore: upgrade Xcode 16 on bitrise.yml" ([#14012](https://github.com/MetaMask/metamask-mobile/pull/14012)) +- fix(bridge): hide staked native assets from token selectors ([#14457](https://github.com/MetaMask/metamask-mobile/pull/14457)) + + +## [7.43.0] + +### Added + +- feat(ramp): estimate gasLimit for ERC20 transfers (sell feature) ([#12467](https://github.com/MetaMask/metamask-mobile/pull/12467)) +- feat(snaps): Add Snap UI Skeleton component integration and mapping ([#13966](https://github.com/MetaMask/metamask-mobile/pull/13966)) +- feat(snaps): Add icon next to SnapUILink ([#13878](https://github.com/MetaMask/metamask-mobile/pull/13878)) +- feat(snaps): Add Snap UI Spinner component ([#13832](https://github.com/MetaMask/metamask-mobile/pull/13832)) +- feat(ramp): payment method selector UI update ([#13722](https://github.com/MetaMask/metamask-mobile/pull/13722)) +- feat(snaps): Add support for full border radius for SnapUIImage ([#13816](https://github.com/MetaMask/metamask-mobile/pull/13816)) +- feat(ramp): enable non-evm support for Ramp, buy only ([#13718](https://github.com/MetaMask/metamask-mobile/pull/13718)) +- feat: Add confirmation UI metrics infra and some redesigned staking deposit events ([#13919](https://github.com/MetaMask/metamask-mobile/pull/13919)) +- feat: Add gas included swaps ([#13972](https://github.com/MetaMask/metamask-mobile/pull/13972)) +- feat: Add Base to Smart Transaction supported chains ([#13920](https://github.com/MetaMask/metamask-mobile/pull/13920)) +- feat: Add token list item pressed event ([#13808](https://github.com/MetaMask/metamask-mobile/pull/13808)) +- feat: STAKE-934 update staking hooks to consume earn controller selectors ([#13939](https://github.com/MetaMask/metamask-mobile/pull/13939)) +- feat: adding skeleton component ([#13780](https://github.com/MetaMask/metamask-mobile/pull/13780)) +- feat: Implement unstaking confirmation ([#13921](https://github.com/MetaMask/metamask-mobile/pull/13921)) +- feat: revisit currencies list ([#13879](https://github.com/MetaMask/metamask-mobile/pull/13879)) +- feat: bridge input screen ([#13847](https://github.com/MetaMask/metamask-mobile/pull/13847)) +- feat: Implement tooltip component on mobile ([#13860](https://github.com/MetaMask/metamask-mobile/pull/13860)) +- feat: support DAI while it's being deprecated ([#13666](https://github.com/MetaMask/metamask-mobile/pull/13666)) +- feat: Implement redesigned staking withdrawals component ([#13826](https://github.com/MetaMask/metamask-mobile/pull/13826)) +- feat: bump profile-sync-controller and migrate to the controller init pattern ([#13859](https://github.com/MetaMask/metamask-mobile/pull/13859)) +- feat: Multi chain send flow ([#13854](https://github.com/MetaMask/metamask-mobile/pull/13854)) +- feat: STAKE-934: added earn-controller pooled staking selectors ([#13875](https://github.com/MetaMask/metamask-mobile/pull/13875)) +- feat: STAKE-934 add earn controller to engine ([#13778](https://github.com/MetaMask/metamask-mobile/pull/13778)) +- feat: bump @metamask/notification-services-controller to 2.0.0 ([#13857](https://github.com/MetaMask/metamask-mobile/pull/13857)) +- feat: add bridge controllers to Engine ([#13750](https://github.com/MetaMask/metamask-mobile/pull/13750)) +- feat: add InlineAlert component ([#13709](https://github.com/MetaMask/metamask-mobile/pull/13709)) +- feat: add MultipleAlertModal component ([#13683](https://github.com/MetaMask/metamask-mobile/pull/13683)) +- feat: Add Snaps UI `Selector` component ([#13747](https://github.com/MetaMask/metamask-mobile/pull/13747)) +- feat: added **/**mocks**/** to sonar.coverage.exclusions ([#13787](https://github.com/MetaMask/metamask-mobile/pull/13787)) +- feat: add `GeneralAlertBanner` component ([#13627](https://github.com/MetaMask/metamask-mobile/pull/13627)) + +### Fixed + +- fix(close bug report action): target branch name has been renamed stable ([#13755](https://github.com/MetaMask/metamask-mobile/pull/13755)) +- fix(sentry sampling): reduce by 25% our sentry trace sample rate to avoid exceeding our quota ([#13745](https://github.com/MetaMask/metamask-mobile/pull/13745)) +- fix(deps): unpin ethereumjs-abi@0.6,x ethereumjs-util@6.x ([#11972](https://github.com/MetaMask/metamask-mobile/pull/11972)) +- fix: Uppercase currency code ([#13967](https://github.com/MetaMask/metamask-mobile/pull/13967)) +- fix: Max balance for dApp erc20 approval ([#13881](https://github.com/MetaMask/metamask-mobile/pull/13881)) +- fix: fix network filter on switch network from dapp ([#13987](https://github.com/MetaMask/metamask-mobile/pull/13987)) +- fix: Move the SnapExecutionService render up in the stack ([#13998](https://github.com/MetaMask/metamask-mobile/pull/13998)) +- fix: Manage order for app services initialization ([#13912](https://github.com/MetaMask/metamask-mobile/pull/13912)) +- fix: use correct updating text when toggling notifications ([#13943](https://github.com/MetaMask/metamask-mobile/pull/13943)) +- fix: cp-7.42.0 fix history transactions loading ([#13959](https://github.com/MetaMask/metamask-mobile/pull/13959)) +- fix: error when asset chain is not available in account controller state ([#13951](https://github.com/MetaMask/metamask-mobile/pull/13951)) +- fix: margin incrementally applied to icon when bottom sheet opened ([#13946](https://github.com/MetaMask/metamask-mobile/pull/13946)) +- fix: STX swap failures when needing to approve erc20 ([#13653](https://github.com/MetaMask/metamask-mobile/pull/13653)) +- fix: cp-7.42.0 Move AssetsPollingProvider down a level to persist tab label ([#13962](https://github.com/MetaMask/metamask-mobile/pull/13962)) +- fix: MMASSETS-626-new-rpc-no-confirmation ([#13883](https://github.com/MetaMask/metamask-mobile/pull/13883)) +- fix: Use proper implementation for `getUnlockPromise` ([#13947](https://github.com/MetaMask/metamask-mobile/pull/13947)) +- fix: Migration of `TransactionController` to modularised controller init ([#13817](https://github.com/MetaMask/metamask-mobile/pull/13817)) +- fix: cp-7.42.0`Tokens` screen performance degradation ([#13907](https://github.com/MetaMask/metamask-mobile/pull/13907)) +- fix: Confirm ScrollView and readd drag down and backdrop click to close ([#13913](https://github.com/MetaMask/metamask-mobile/pull/13913)) +- fix: Persist scrypt derived storage keys to Keychain/Keystore on iOS/Android ([#13899](https://github.com/MetaMask/metamask-mobile/pull/13899)) +- fix: cp-7.42.0 enable notifications UI ([#13877](https://github.com/MetaMask/metamask-mobile/pull/13877)) +- fix: main balance formatting ([#13818](https://github.com/MetaMask/metamask-mobile/pull/13818)) +- fix: cp-7.42.0 Display account label in re-designs confirmation page account info section ([#13853](https://github.com/MetaMask/metamask-mobile/pull/13853)) +- fix: add autoscroll in RPC URL form when virtual keyboard blocks content ([#13831](https://github.com/MetaMask/metamask-mobile/pull/13831)) +- fix: Missing POL percentage trend ([#13812](https://github.com/MetaMask/metamask-mobile/pull/13812)) +- fix: cp-7.42.0 Disable signature re-designs for ledger account ([#13858](https://github.com/MetaMask/metamask-mobile/pull/13858)) +- fix: prevent network selector modal from going behind IOS keyboard ([#13810](https://github.com/MetaMask/metamask-mobile/pull/13810)) +- fix: Permit Simulation vertical overflow, title padding, and collapsed message alignment ([#13830](https://github.com/MetaMask/metamask-mobile/pull/13830)) +- fix: Deal with a couple of crashes when rendering Snaps UI ([#13828](https://github.com/MetaMask/metamask-mobile/pull/13828)) +- fix: Multichain balances ([#13742](https://github.com/MetaMask/metamask-mobile/pull/13742)) +- fix: tsdoc multi rpc for non evm networks ([#13688](https://github.com/MetaMask/metamask-mobile/pull/13688)) +- fix: Improve Snaps UI spacing rules ([#13797](https://github.com/MetaMask/metamask-mobile/pull/13797)) +- fix: cp-7.42.0 improve performance of notifications loading when opening the app ([#13803](https://github.com/MetaMask/metamask-mobile/pull/13803)) +- fix: Redesign Confirmation bold font weight text ([#13706](https://github.com/MetaMask/metamask-mobile/pull/13706)) +- fix: receive network name in receive asset screen ([#13746](https://github.com/MetaMask/metamask-mobile/pull/13746)) +- fix: fix setup files ([#13799](https://github.com/MetaMask/metamask-mobile/pull/13799)) +- fix: fix balance display in account info signature request ([#13740](https://github.com/MetaMask/metamask-mobile/pull/13740)) +- fix: Remove `transactionMetrics` from persisted storage ([#13793](https://github.com/MetaMask/metamask-mobile/pull/13793)) +- fix: cp-7.42.0 push notification settings bugs ([#13772](https://github.com/MetaMask/metamask-mobile/pull/13772)) +- fix: bitrise missing signature elements following BottomModal → BottomSheet refactor ([#13783](https://github.com/MetaMask/metamask-mobile/pull/13783)) +- fix: permit simulation overflow ([#13769](https://github.com/MetaMask/metamask-mobile/pull/13769)) +- fix: Improve redesigned staking deposit confirmation navigation ([#13743](https://github.com/MetaMask/metamask-mobile/pull/13743)) +- fix: fixes ramp quote selection test ([#13756](https://github.com/MetaMask/metamask-mobile/pull/13756)) + ## [7.42.1] ### Fixed @@ -5092,7 +5348,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#957](https://github.com/MetaMask/metamask-mobile/pull/957): fix timeouts (#957) - [#954](https://github.com/MetaMask/metamask-mobile/pull/954): Bugfix: onboarding navigation (#954) -[Unreleased]: https://github.com/MetaMask/metamask-mobile/compare/v7.42.0...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-mobile/compare/v7.45.0...HEAD +[7.45.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.44.0...v7.45.0 +[7.44.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.43.0...v7.44.0 +[7.43.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.42.1...v7.43.0 +[7.42.1]: https://github.com/MetaMask/metamask-mobile/compare/v7.42.0...v7.42.1 [7.42.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.41.0...v7.42.0 [7.41.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.40.0...v7.41.0 [7.40.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.39.0...v7.40.0 diff --git a/README.md b/README.md index e60e59241ef..d068c60ac5c 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ To learn how to contribute to the MetaMask codebase, visit our [Contributor Docs - [Build Troubleshooting](./docs/readme/troubleshooting.md) - [Testing](./docs/readme/testing.md) - [Debugging](./docs/readme/debugging.md) +- [API Call Logging for Debugging](./docs/readme/api-logging.md) - [Storybook](./docs/readme/storybook.md) - [Miscellaneous](./docs/readme/miscellaneous.md) @@ -96,7 +97,7 @@ cd metamask-mobile ##### Firebase Messaging Setup -MetaMask uses Firebase Cloud Messaging (FCM) to enable app communications. To integrate FCM, you’ll need configuration files for both iOS and Android platforms. +MetaMask uses Firebase Cloud Messaging (FCM) to enable app communications. To integrate FCM, you'll need configuration files for both iOS and Android platforms. ###### Internal Contributor instructions diff --git a/android/app/build.gradle b/android/app/build.gradle index 0c6e2b66522..34ecc9634fc 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -178,8 +178,8 @@ android { applicationId "io.metamask" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionName "7.42.99" - versionCode 1623 + versionName "7.45.0" + versionCode 1724 testBuildType System.getProperty('testBuildType', 'debug') missingDimensionStrategy 'react-native-camera', 'general' testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/android/app/src/main/assets/fonts/EuclidCircularB-Bold.otf b/android/app/src/main/assets/fonts/EuclidCircularB-Bold.otf deleted file mode 100644 index 6d6297a83d1..00000000000 Binary files a/android/app/src/main/assets/fonts/EuclidCircularB-Bold.otf and /dev/null differ diff --git a/android/app/src/main/assets/fonts/EuclidCircularB-BoldItalic.otf b/android/app/src/main/assets/fonts/EuclidCircularB-BoldItalic.otf deleted file mode 100644 index 2ff2c9c4246..00000000000 Binary files a/android/app/src/main/assets/fonts/EuclidCircularB-BoldItalic.otf and /dev/null differ diff --git a/android/app/src/main/assets/fonts/EuclidCircularB-Light.otf b/android/app/src/main/assets/fonts/EuclidCircularB-Light.otf deleted file mode 100644 index b430571f9b4..00000000000 Binary files a/android/app/src/main/assets/fonts/EuclidCircularB-Light.otf and /dev/null differ diff --git a/android/app/src/main/assets/fonts/EuclidCircularB-LightItalic.otf b/android/app/src/main/assets/fonts/EuclidCircularB-LightItalic.otf deleted file mode 100644 index 3cf9be629d9..00000000000 Binary files a/android/app/src/main/assets/fonts/EuclidCircularB-LightItalic.otf and /dev/null differ diff --git a/android/app/src/main/assets/fonts/EuclidCircularB-Medium.otf b/android/app/src/main/assets/fonts/EuclidCircularB-Medium.otf deleted file mode 100644 index 9f7c453210a..00000000000 Binary files a/android/app/src/main/assets/fonts/EuclidCircularB-Medium.otf and /dev/null differ diff --git a/android/app/src/main/assets/fonts/EuclidCircularB-MediumItalic.otf b/android/app/src/main/assets/fonts/EuclidCircularB-MediumItalic.otf deleted file mode 100644 index c249a488fee..00000000000 Binary files a/android/app/src/main/assets/fonts/EuclidCircularB-MediumItalic.otf and /dev/null differ diff --git a/android/app/src/main/assets/fonts/EuclidCircularB-Regular.otf b/android/app/src/main/assets/fonts/EuclidCircularB-Regular.otf deleted file mode 100644 index ca09e0424b7..00000000000 Binary files a/android/app/src/main/assets/fonts/EuclidCircularB-Regular.otf and /dev/null differ diff --git a/android/app/src/main/assets/fonts/EuclidCircularB-RegularItalic.otf b/android/app/src/main/assets/fonts/EuclidCircularB-RegularItalic.otf deleted file mode 100644 index 5af11569355..00000000000 Binary files a/android/app/src/main/assets/fonts/EuclidCircularB-RegularItalic.otf and /dev/null differ diff --git a/android/app/src/main/assets/fonts/EuclidCircularB-Semibold.otf b/android/app/src/main/assets/fonts/EuclidCircularB-Semibold.otf deleted file mode 100644 index 8f1145d2c99..00000000000 Binary files a/android/app/src/main/assets/fonts/EuclidCircularB-Semibold.otf and /dev/null differ diff --git a/android/app/src/main/assets/fonts/EuclidCircularB-SemiboldItalic.otf b/android/app/src/main/assets/fonts/EuclidCircularB-SemiboldItalic.otf deleted file mode 100644 index 85bd6210c68..00000000000 Binary files a/android/app/src/main/assets/fonts/EuclidCircularB-SemiboldItalic.otf and /dev/null differ diff --git a/android/app/src/main/assets/fonts/MMPoly-Regular.otf b/android/app/src/main/assets/fonts/MMPoly-Regular.otf new file mode 100755 index 00000000000..2525509935c Binary files /dev/null and b/android/app/src/main/assets/fonts/MMPoly-Regular.otf differ diff --git a/android/app/src/main/assets/fonts/MMSans-Bold.otf b/android/app/src/main/assets/fonts/MMSans-Bold.otf new file mode 100755 index 00000000000..201f5ae59f6 Binary files /dev/null and b/android/app/src/main/assets/fonts/MMSans-Bold.otf differ diff --git a/android/app/src/main/assets/fonts/MMSans-Medium.otf b/android/app/src/main/assets/fonts/MMSans-Medium.otf new file mode 100755 index 00000000000..75d1bb210a9 Binary files /dev/null and b/android/app/src/main/assets/fonts/MMSans-Medium.otf differ diff --git a/android/app/src/main/assets/fonts/Roboto-Black.ttf b/android/app/src/main/assets/fonts/Roboto-Black.ttf deleted file mode 100755 index 689fe5cb3c7..00000000000 Binary files a/android/app/src/main/assets/fonts/Roboto-Black.ttf and /dev/null differ diff --git a/android/app/src/main/assets/fonts/Roboto-BlackItalic.ttf b/android/app/src/main/assets/fonts/Roboto-BlackItalic.ttf deleted file mode 100755 index 0b4e0ee1088..00000000000 Binary files a/android/app/src/main/assets/fonts/Roboto-BlackItalic.ttf and /dev/null differ diff --git a/android/app/src/main/assets/fonts/Roboto-Bold.ttf b/android/app/src/main/assets/fonts/Roboto-Bold.ttf deleted file mode 100755 index d3f01ad245b..00000000000 Binary files a/android/app/src/main/assets/fonts/Roboto-Bold.ttf and /dev/null differ diff --git a/android/app/src/main/assets/fonts/Roboto-BoldItalic.ttf b/android/app/src/main/assets/fonts/Roboto-BoldItalic.ttf deleted file mode 100755 index 41cc1e75315..00000000000 Binary files a/android/app/src/main/assets/fonts/Roboto-BoldItalic.ttf and /dev/null differ diff --git a/android/app/src/main/assets/fonts/Roboto-Italic.ttf b/android/app/src/main/assets/fonts/Roboto-Italic.ttf deleted file mode 100755 index 6a1cee5b294..00000000000 Binary files a/android/app/src/main/assets/fonts/Roboto-Italic.ttf and /dev/null differ diff --git a/android/app/src/main/assets/fonts/Roboto-Light.ttf b/android/app/src/main/assets/fonts/Roboto-Light.ttf deleted file mode 100755 index 219063a578a..00000000000 Binary files a/android/app/src/main/assets/fonts/Roboto-Light.ttf and /dev/null differ diff --git a/android/app/src/main/assets/fonts/Roboto-LightItalic.ttf b/android/app/src/main/assets/fonts/Roboto-LightItalic.ttf deleted file mode 100755 index 0e81e876fca..00000000000 Binary files a/android/app/src/main/assets/fonts/Roboto-LightItalic.ttf and /dev/null differ diff --git a/android/app/src/main/assets/fonts/Roboto-Medium.ttf b/android/app/src/main/assets/fonts/Roboto-Medium.ttf deleted file mode 100755 index 1a7f3b0bba4..00000000000 Binary files a/android/app/src/main/assets/fonts/Roboto-Medium.ttf and /dev/null differ diff --git a/android/app/src/main/assets/fonts/Roboto-MediumItalic.ttf b/android/app/src/main/assets/fonts/Roboto-MediumItalic.ttf deleted file mode 100755 index 003029527cc..00000000000 Binary files a/android/app/src/main/assets/fonts/Roboto-MediumItalic.ttf and /dev/null differ diff --git a/android/app/src/main/assets/fonts/Roboto-Regular.ttf b/android/app/src/main/assets/fonts/Roboto-Regular.ttf deleted file mode 100755 index 2c97eeadffe..00000000000 Binary files a/android/app/src/main/assets/fonts/Roboto-Regular.ttf and /dev/null differ diff --git a/android/app/src/main/assets/fonts/Roboto-Thin.ttf b/android/app/src/main/assets/fonts/Roboto-Thin.ttf deleted file mode 100755 index b74a4fd1a2e..00000000000 Binary files a/android/app/src/main/assets/fonts/Roboto-Thin.ttf and /dev/null differ diff --git a/android/app/src/main/assets/fonts/Roboto-ThinItalic.ttf b/android/app/src/main/assets/fonts/Roboto-ThinItalic.ttf deleted file mode 100755 index dd0ddb85264..00000000000 Binary files a/android/app/src/main/assets/fonts/Roboto-ThinItalic.ttf and /dev/null differ diff --git a/android/link-assets-manifest.json b/android/link-assets-manifest.json index 24f6f419d9c..a1d9071736e 100644 --- a/android/link-assets-manifest.json +++ b/android/link-assets-manifest.json @@ -26,44 +26,16 @@ "sha1": "c129a146979b642a446574e109b7bcdd8516d5d7" }, { - "path": "app/fonts/EuclidCircularB-Bold.otf", - "sha1": "7c2a5137fdc62618d404ac0cb54f8e732cc43161" + "path": "app/fonts/MMPoly-Regular.otf", + "sha1": "b6cd0bc868fe5f53469bf52246917210c807954d" }, { - "path": "app/fonts/EuclidCircularB-BoldItalic.otf", - "sha1": "77ee92e4787cdf77c2226b9d68fe5374505bd1d0" + "path": "app/fonts/MMSans-Bold.otf", + "sha1": "048a70c36b9a3453853ecff2ded9b0e88b411dc0" }, { - "path": "app/fonts/EuclidCircularB-Light.otf", - "sha1": "21fd3c7c27918511ef81a5e695ce93e6ff631c0b" - }, - { - "path": "app/fonts/EuclidCircularB-LightItalic.otf", - "sha1": "6f4e697f65c6d82caf50a31fed1539f3aef733b7" - }, - { - "path": "app/fonts/EuclidCircularB-Medium.otf", - "sha1": "0a2cdb45ab1ce34570c534738f651ac7c57f6030" - }, - { - "path": "app/fonts/EuclidCircularB-MediumItalic.otf", - "sha1": "fe33bcd91e81d7af20132b4ce1ac5918a11a6626" - }, - { - "path": "app/fonts/EuclidCircularB-Regular.otf", - "sha1": "53316f985467975048f477e4afb784ef64b32e84" - }, - { - "path": "app/fonts/EuclidCircularB-RegularItalic.otf", - "sha1": "d9f41cb3b281386fc07d8210a8d32b6a8965b91c" - }, - { - "path": "app/fonts/EuclidCircularB-Semibold.otf", - "sha1": "bc129f9126a356707aa8a50e585cb075fd1740e9" - }, - { - "path": "app/fonts/EuclidCircularB-SemiboldItalic.otf", - "sha1": "77f2e0212711cc8e043acabdc4bd4a264dfeeeb7" + "path": "app/fonts/MMSans-Medium.otf", + "sha1": "4a304a2ce85a51be718c56ec71e7cad713ab7f84" }, { "path": "app/fonts/MMSans-Regular.otf", @@ -73,54 +45,6 @@ "path": "app/fonts/Metamask.ttf", "sha1": "d274323055489d231d009cb3aa7ccfba3620e340" }, - { - "path": "app/fonts/Roboto-Black.ttf", - "sha1": "c572416b9587c40d49ea60c7128f7f17b9317ad8" - }, - { - "path": "app/fonts/Roboto-BlackItalic.ttf", - "sha1": "6c8acc36bbdf17bcd6a33756aa42e2557bb3f805" - }, - { - "path": "app/fonts/Roboto-Bold.ttf", - "sha1": "0ce37ced9c5fcac9bdc452a432c1258870ba4677" - }, - { - "path": "app/fonts/Roboto-BoldItalic.ttf", - "sha1": "8cd79e47ed8a9f9ea79ffa186852ad7cbad5687f" - }, - { - "path": "app/fonts/Roboto-Italic.ttf", - "sha1": "0213e38dffde2a0a5672d84fb62c6aa994e38c3b" - }, - { - "path": "app/fonts/Roboto-Light.ttf", - "sha1": "73a2bb2d6e591a90ffb4ed118a3989fb17b54c7b" - }, - { - "path": "app/fonts/Roboto-LightItalic.ttf", - "sha1": "037ef2bf307642203858dd252fc46eb400684f02" - }, - { - "path": "app/fonts/Roboto-Medium.ttf", - "sha1": "5f16f4d6dbb4a4f12d8ae96488ac209bb49762a5" - }, - { - "path": "app/fonts/Roboto-MediumItalic.ttf", - "sha1": "cab617eccf6db0396675ec9c42e747a4738f059f" - }, - { - "path": "app/fonts/Roboto-Regular.ttf", - "sha1": "dd1b1db13ff1f72138c134c62f38fef83749f36a" - }, - { - "path": "app/fonts/Roboto-Thin.ttf", - "sha1": "9514ad7aee341594f43a33893f0b3d8a6d81f32e" - }, - { - "path": "app/fonts/Roboto-ThinItalic.ttf", - "sha1": "c9297d2166618da2b66a06bacfcbd50b68581e6f" - }, { "path": "app/fonts/config.json", "sha1": "47efd6cacd9d899349b5b491425b288619ba712d" diff --git a/app/actions/identity/index.test.ts b/app/actions/identity/index.test.ts index bbd9017e277..4aaf3c190fc 100644 --- a/app/actions/identity/index.test.ts +++ b/app/actions/identity/index.test.ts @@ -3,6 +3,7 @@ import { performSignOut, disableProfileSyncing, enableProfileSyncing, + syncInternalAccountsWithUserStorage, } from '.'; import Engine from '../../core/Engine'; @@ -16,6 +17,7 @@ jest.mock('../../core/Engine', () => ({ UserStorageController: { enableProfileSyncing: jest.fn(), disableProfileSyncing: jest.fn(), + syncInternalAccountsWithUserStorage: jest.fn(), }, }, })); @@ -75,4 +77,18 @@ describe('Identity actions', () => { ).toHaveBeenCalled(); expect(result).toBeUndefined(); }); + + it('syncs internal accounts with user storage', async () => { + ( + Engine.context.UserStorageController + .syncInternalAccountsWithUserStorage as jest.Mock + ).mockResolvedValue(undefined); + + const result = await syncInternalAccountsWithUserStorage(); + + expect( + Engine.context.UserStorageController.syncInternalAccountsWithUserStorage, + ).toHaveBeenCalled(); + expect(result).toBeUndefined(); + }); }); diff --git a/app/actions/identity/index.ts b/app/actions/identity/index.ts index e0b346d9d13..657b478c110 100644 --- a/app/actions/identity/index.ts +++ b/app/actions/identity/index.ts @@ -32,3 +32,23 @@ export const disableProfileSyncing = async () => { return getErrorMessage(error); } }; + +export const syncInternalAccountsWithUserStorage = async () => { + try { + await Engine.context.UserStorageController.syncInternalAccountsWithUserStorage(); + } catch (error) { + return getErrorMessage(error); + } +}; + +export const setIsAccountSyncingReadyToBeDispatched = async ( + isAccountSyncingReadyToBeDispatched: boolean, +) => { + try { + await Engine.context.UserStorageController.setIsAccountSyncingReadyToBeDispatched( + isAccountSyncingReadyToBeDispatched, + ); + } catch (error) { + return getErrorMessage(error); + } +}; diff --git a/app/actions/multiSrp/index.test.ts b/app/actions/multiSrp/index.test.ts index 361a275dfbf..a700b07d6d4 100644 --- a/app/actions/multiSrp/index.test.ts +++ b/app/actions/multiSrp/index.test.ts @@ -4,6 +4,7 @@ import Engine from '../../core/Engine'; import { importNewSecretRecoveryPhrase, createNewSecretRecoveryPhrase, + addNewHdAccount, } from './'; import { wordlist } from '@metamask/scure-bip39/dist/wordlists/english'; @@ -12,20 +13,34 @@ jest.mock('../../util/Logger'); const mockSetSelectedAddress = jest.fn(); const mockAddNewKeyring = jest.fn(); const mockGetKeyringsByType = jest.fn(); -const mockWithKeyring = jest.fn(); const mockGetAccounts = jest.fn(); +const mockAddAccounts = jest.fn(); +const mockSetAccountLabel = jest.fn(); + +const hdKeyring = { + getAccounts: () => { + mockGetAccounts(); + return ['0x123']; + }, + addAccounts: (n: number) => { + mockAddAccounts(n); + return ['0x123']; + }, +}; + jest.mock('../../core/Engine', () => ({ context: { KeyringController: { addNewKeyring: (keyringType: ExtendedKeyringTypes, args: unknown) => mockAddNewKeyring(keyringType, args), getKeyringsByType: () => mockGetKeyringsByType(), - // eslint-disable-next-line @typescript-eslint/no-explicit-any - withKeyring: (args: any) => mockWithKeyring(args), - getAccounts: () => mockGetAccounts(), + withKeyring: (_selector: unknown, operation: (args: unknown) => void) => + operation({ keyring: hdKeyring, metadata: { id: '1234' } }), }, }, setSelectedAddress: (address: string) => mockSetSelectedAddress(address), + setAccountLabel: (address: string, label: string) => + mockSetAccountLabel(address, label), })); jest.mocked(Engine); @@ -96,4 +111,54 @@ describe('MultiSRP Actions', () => { expect(mockSetSelectedAddress).not.toHaveBeenCalled(); }); }); + + describe('addNewHdAccount', () => { + it('adds a new HD account and sets the selected address', async () => { + mockAddAccounts.mockReturnValue([testAddress]); + + await addNewHdAccount(); + + expect(mockAddAccounts).toHaveBeenCalledWith(1); + expect(mockSetSelectedAddress).toHaveBeenCalledWith(testAddress); + }); + + it('adds a new HD account with a specific keyring ID and sets the selected address', async () => { + const keyringId = 'test-keyring-id'; + mockAddAccounts.mockReturnValue([testAddress]); + + await addNewHdAccount(keyringId); + + expect(mockAddAccounts).toHaveBeenCalledWith(1); + expect(mockSetSelectedAddress).toHaveBeenCalledWith(testAddress); + }); + + it('adds a new HD account and sets the account label if a name is provided', async () => { + const accountName = 'Test Account'; + mockAddAccounts.mockReturnValue([testAddress]); + + await addNewHdAccount(undefined, accountName); + + expect(mockAddAccounts).toHaveBeenCalledWith(1); + expect(mockSetSelectedAddress).toHaveBeenCalledWith(testAddress); + expect(mockSetAccountLabel).toHaveBeenCalledWith( + testAddress, + accountName, + ); + }); + + it('adds a new HD account with a specific keyring ID and sets the account label if a name is provided', async () => { + const keyringId = 'test-keyring-id'; + const accountName = 'Test Account'; + mockAddAccounts.mockReturnValue([testAddress]); + + await addNewHdAccount(keyringId, accountName); + + expect(mockAddAccounts).toHaveBeenCalledWith(1); + expect(mockSetSelectedAddress).toHaveBeenCalledWith(testAddress); + expect(mockSetAccountLabel).toHaveBeenCalledWith( + testAddress, + accountName, + ); + }); + }); }); diff --git a/app/actions/multiSrp/index.ts b/app/actions/multiSrp/index.ts index 7dc5c64b34a..5d6603902fe 100644 --- a/app/actions/multiSrp/index.ts +++ b/app/actions/multiSrp/index.ts @@ -1,9 +1,8 @@ import { HdKeyring } from '@metamask/eth-hd-keyring'; -import { Json } from '@metamask/eth-query'; -import { EthKeyring } from '@metamask/keyring-internal-api'; import { wordlist } from '@metamask/scure-bip39/dist/wordlists/english'; import ExtendedKeyringTypes from '../../constants/keyringTypes'; import Engine from '../../core/Engine'; +import { KeyringSelector } from '@metamask/keyring-controller'; export async function importNewSecretRecoveryPhrase(mnemonic: string) { const { KeyringController } = Engine.context; @@ -38,23 +37,60 @@ export async function importNewSecretRecoveryPhrase(mnemonic: string) { throw new Error('This mnemonic has already been imported.'); } - const newKeyring = (await KeyringController.addNewKeyring( + const newKeyring = await KeyringController.addNewKeyring( ExtendedKeyringTypes.hd, { mnemonic, numberOfAccounts: 1, }, - )) as EthKeyring; - const [newAccountAddress] = await newKeyring.getAccounts(); + ); + + const [newAccountAddress] = await KeyringController.withKeyring( + { + id: newKeyring.id, + }, + async ({ keyring }) => keyring.getAccounts(), + ); + return Engine.setSelectedAddress(newAccountAddress); } export async function createNewSecretRecoveryPhrase() { const { KeyringController } = Engine.context; - const newHdkeyring = (await KeyringController.addNewKeyring( + const newHdkeyring = await KeyringController.addNewKeyring( ExtendedKeyringTypes.hd, - )) as HdKeyring; + ); + + const [newAccountAddress] = await KeyringController.withKeyring( + { + id: newHdkeyring.id, + }, + async ({ keyring }) => keyring.getAccounts(), + ); - const newAccountAddress = (await newHdkeyring.getAccounts())[0]; return Engine.setSelectedAddress(newAccountAddress); } + +export async function addNewHdAccount( + keyringId?: string, + name?: string, +): Promise { + const { KeyringController } = Engine.context; + const keyringSelector: KeyringSelector = keyringId + ? { + id: keyringId, + } + : { + type: ExtendedKeyringTypes.hd, + }; + + const [addedAccountAddress] = await KeyringController.withKeyring( + keyringSelector, + async ({ keyring }) => await keyring.addAccounts(1), + ); + Engine.setSelectedAddress(addedAccountAddress); + + if (name) { + Engine.setAccountLabel(addedAccountAddress, name); + } +} diff --git a/app/actions/multichain/state.ts b/app/actions/multichain/state.ts deleted file mode 100644 index a2015e89b59..00000000000 --- a/app/actions/multichain/state.ts +++ /dev/null @@ -1,7 +0,0 @@ -///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) -export interface MultichainSettingsState { - bitcoinSupportEnabled: boolean; - bitcoinTestnetSupportEnabled: boolean; - solanaSupportEnabled: boolean; -} -///: END:ONLY_INCLUDE_IF diff --git a/app/actions/onboarding/index.test.ts b/app/actions/onboarding/index.test.ts new file mode 100644 index 00000000000..635a23d45f1 --- /dev/null +++ b/app/actions/onboarding/index.test.ts @@ -0,0 +1,41 @@ +import { + saveOnboardingEvent, + clearOnboardingEvents, + setCompletedOnboarding, + SAVE_EVENT, + CLEAR_EVENTS, + SET_COMPLETED_ONBOARDING, +} from '.'; +import { ITrackingEvent } from '../../core/Analytics/MetaMetrics.types'; + +describe('Onboarding actions', () => { + describe('saveOnboardingEvent', () => { + it('creates an action to save onboarding events', () => { + const mockEvent = { + name: 'test_event', + } as ITrackingEvent; + expect(saveOnboardingEvent([mockEvent])).toEqual({ + type: SAVE_EVENT, + event: [mockEvent], + }); + }); + }); + + describe('clearOnboardingEvents', () => { + it('creates an action to clear onboarding events', () => { + expect(clearOnboardingEvents()).toEqual({ + type: CLEAR_EVENTS, + }); + }); + }); + + describe('setCompletedOnboarding', () => { + it('creates an action to set completedOnboarding', () => { + const completedOnboarding = true; + expect(setCompletedOnboarding(completedOnboarding)).toEqual({ + type: SET_COMPLETED_ONBOARDING, + completedOnboarding, + }); + }); + }); +}); diff --git a/app/actions/onboarding/index.ts b/app/actions/onboarding/index.ts index 8b1e2c3e6e0..ea149b87994 100644 --- a/app/actions/onboarding/index.ts +++ b/app/actions/onboarding/index.ts @@ -2,6 +2,7 @@ import { ITrackingEvent } from '../../core/Analytics/MetaMetrics.types'; export const SAVE_EVENT = 'SAVE_EVENT'; export const CLEAR_EVENTS = 'CLEAR_EVENTS'; +export const SET_COMPLETED_ONBOARDING = 'SET_COMPLETED_ONBOARDING'; interface SaveEventAction { type: typeof SAVE_EVENT; @@ -12,7 +13,15 @@ interface ClearEventsAction { type: typeof CLEAR_EVENTS; } -export type OnboardingActionTypes = SaveEventAction | ClearEventsAction; +interface SetCompletedOnboardingAction { + type: typeof SET_COMPLETED_ONBOARDING; + completedOnboarding: boolean; +} + +export type OnboardingActionTypes = + | SaveEventAction + | ClearEventsAction + | SetCompletedOnboardingAction; export function saveOnboardingEvent( eventArgs: [ITrackingEvent], @@ -28,3 +37,12 @@ export function clearOnboardingEvents(): ClearEventsAction { type: CLEAR_EVENTS, }; } + +export function setCompletedOnboarding( + completedOnboarding: boolean, +): SetCompletedOnboardingAction { + return { + type: SET_COMPLETED_ONBOARDING, + completedOnboarding, + }; +} diff --git a/app/actions/signatureRequest/index.ts b/app/actions/signatureRequest/index.ts index db042fef16d..3c98591d8df 100644 --- a/app/actions/signatureRequest/index.ts +++ b/app/actions/signatureRequest/index.ts @@ -1,4 +1,4 @@ -import { SecurityAlertResponse } from '../../components/Views/confirmations/components/BlockaidBanner/BlockaidBanner.types'; +import { SecurityAlertResponse } from '../../components/Views/confirmations/legacy/components/BlockaidBanner/BlockaidBanner.types'; /** * Clears transaction object completely diff --git a/app/component-library/base-components/TagBase/__snapshots__/TagBase.test.tsx.snap b/app/component-library/base-components/TagBase/__snapshots__/TagBase.test.tsx.snap index a3df343ffb5..28c295731e4 100644 --- a/app/component-library/base-components/TagBase/__snapshots__/TagBase.test.tsx.snap +++ b/app/component-library/base-components/TagBase/__snapshots__/TagBase.test.tsx.snap @@ -9,10 +9,10 @@ exports[`TagBase should render TagBase 1`] = ` { "alignSelf": "flex-start", "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 999, "borderWidth": 0, - "color": "#141618", + "color": "#121314", "padding": 16, "paddingHorizontal": 8, "paddingVertical": 2, @@ -29,7 +29,7 @@ exports[`TagBase should render TagBase 1`] = ` } > @@ -50,7 +50,7 @@ exports[`ButtonToggle renders correctly in inactive state 1`] = ` "alignItems": "center", "alignSelf": "flex-start", "backgroundColor": "transparent", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 20, "borderWidth": 1, "flexDirection": "row", @@ -64,12 +64,12 @@ exports[`ButtonToggle renders correctly in inactive state 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > diff --git a/app/component-library/components-temp/CellSelectWithMenu/__snapshots__/CellSelectWithMenu.test.tsx.snap b/app/component-library/components-temp/CellSelectWithMenu/__snapshots__/CellSelectWithMenu.test.tsx.snap index 036368b43bd..d46d2efccd9 100644 --- a/app/component-library/components-temp/CellSelectWithMenu/__snapshots__/CellSelectWithMenu.test.tsx.snap +++ b/app/component-library/components-temp/CellSelectWithMenu/__snapshots__/CellSelectWithMenu.test.tsx.snap @@ -209,8 +209,8 @@ exports[`CellSelectWithMenu should render with default settings correctly 1`] = numberOfLines={1} style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", + "color": "#121314", + "fontFamily": "CentraNo1-Book", "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, @@ -254,19 +254,19 @@ exports[`CellSelectWithMenu should render with default settings correctly 1`] = numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > 0x2990079bcdEe240329a520d2444386FC119da21a @@ -343,7 +343,7 @@ exports[`CellSelectWithMenu should render with default settings correctly 1`] = testID="button-menu-select-test-id" > diff --git a/app/component-library/components-temp/CustomSpendCap/CustomInput/CustomInput.styles.ts b/app/component-library/components-temp/CustomSpendCap/CustomInput/CustomInput.styles.ts index 237d3db4b58..63bb0d923c0 100644 --- a/app/component-library/components-temp/CustomSpendCap/CustomInput/CustomInput.styles.ts +++ b/app/component-library/components-temp/CustomSpendCap/CustomInput/CustomInput.styles.ts @@ -2,6 +2,7 @@ import { StyleSheet, TextStyle } from 'react-native'; import { Theme } from '../../../../util/theme/models'; +import { getFontFamily, TextVariant } from '../../../components/Texts/Text'; /** * Style sheet for Custom Input component. * @@ -35,6 +36,7 @@ const styleSheet = (params: { theme: Theme }) => { marginRight: 16, color: colors.text.default, ...typography.sBodyMD, + fontFamily: getFontFamily(TextVariant.BodyMD), } as TextStyle, maxValueText: { color: theme.colors.text.alternative, diff --git a/app/component-library/components-temp/CustomSpendCap/CustomInput/__snapshots__/CustomInput.test.tsx.snap b/app/component-library/components-temp/CustomSpendCap/CustomInput/__snapshots__/CustomInput.test.tsx.snap index b530124dbf5..2c14bfdca8c 100644 --- a/app/component-library/components-temp/CustomSpendCap/CustomInput/__snapshots__/CustomInput.test.tsx.snap +++ b/app/component-library/components-temp/CustomSpendCap/CustomInput/__snapshots__/CustomInput.test.tsx.snap @@ -33,13 +33,13 @@ exports[`CustomInput should render correctly 1`] = ` style={ [ { - "color": "#141618", + "color": "#121314", "flexGrow": 1, - "fontFamily": "Euclid Circular B", - "fontSize": 14, + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, "marginRight": 16, "paddingBottom": 0, "paddingTop": 0, @@ -55,7 +55,7 @@ exports[`CustomInput should render correctly 1`] = ` onPress={[Function]} style={ { - "color": "#6a737d", + "color": "#686e7d", } } testID="custom-spend-cap-max-test-id" diff --git a/app/component-library/components-temp/CustomSpendCap/__snapshots__/CustomSpendCap.test.tsx.snap b/app/component-library/components-temp/CustomSpendCap/__snapshots__/CustomSpendCap.test.tsx.snap index 2bdc8856035..bc22b012ed7 100644 --- a/app/component-library/components-temp/CustomSpendCap/__snapshots__/CustomSpendCap.test.tsx.snap +++ b/app/component-library/components-temp/CustomSpendCap/__snapshots__/CustomSpendCap.test.tsx.snap @@ -4,7 +4,7 @@ exports[`CustomSpendCap should match snapshot 1`] = ` @@ -164,19 +164,19 @@ exports[`CustomSpendCap should match snapshot 1`] = ` style={ [ { - "color": "#141618", + "color": "#121314", "flexGrow": 1, - "fontFamily": "Euclid Circular B", - "fontSize": 14, + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, "marginRight": 16, "paddingBottom": 0, "paddingTop": 0, }, { - "color": "#d73847", + "color": "#ca3542", }, ] } @@ -189,12 +189,12 @@ exports[`CustomSpendCap should match snapshot 1`] = ` onPress={[Function]} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } testID="custom-spend-cap-max-test-id" @@ -214,12 +214,12 @@ exports[`CustomSpendCap should match snapshot 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -234,12 +234,12 @@ exports[`CustomSpendCap should match snapshot 1`] = ` style={ { "backgroundColor": "transparent", - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } suppressHighlighting={true} @@ -248,12 +248,12 @@ exports[`CustomSpendCap should match snapshot 1`] = ` accessibilityRole="text" style={ { - "color": "#0376c9", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#4459ff", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > diff --git a/app/component-library/components-temp/KeyValueRow/__snapshots__/KeyValueRow.test.tsx.snap b/app/component-library/components-temp/KeyValueRow/__snapshots__/KeyValueRow.test.tsx.snap index a4c9e5f6bfe..e77bf2bda11 100644 --- a/app/component-library/components-temp/KeyValueRow/__snapshots__/KeyValueRow.test.tsx.snap +++ b/app/component-library/components-temp/KeyValueRow/__snapshots__/KeyValueRow.test.tsx.snap @@ -34,7 +34,7 @@ exports[`KeyValueRow Prebuilt Component KeyValueRow should render text with icon } > diff --git a/app/component-library/components-temp/SegmentedControl/__snapshots__/SegmentedControl.test.tsx.snap b/app/component-library/components-temp/SegmentedControl/__snapshots__/SegmentedControl.test.tsx.snap index 543c41e0a02..87b5eb4cf9a 100644 --- a/app/component-library/components-temp/SegmentedControl/__snapshots__/SegmentedControl.test.tsx.snap +++ b/app/component-library/components-temp/SegmentedControl/__snapshots__/SegmentedControl.test.tsx.snap @@ -36,8 +36,8 @@ exports[`SegmentedControl Multi-select mode renders correctly with default selec { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#0376C91A", - "borderColor": "#0376c9", + "backgroundColor": "#4459ff1a", + "borderColor": "#4459ff", "borderRadius": 20, "borderWidth": 1, "flexDirection": "row", @@ -51,12 +51,12 @@ exports[`SegmentedControl Multi-select mode renders correctly with default selec accessibilityRole="text" style={ { - "color": "#0376c9", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#4459ff", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -83,7 +83,7 @@ exports[`SegmentedControl Multi-select mode renders correctly with default selec "alignItems": "center", "alignSelf": "flex-start", "backgroundColor": "transparent", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 20, "borderWidth": 1, "flexDirection": "row", @@ -97,12 +97,12 @@ exports[`SegmentedControl Multi-select mode renders correctly with default selec accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -128,8 +128,8 @@ exports[`SegmentedControl Multi-select mode renders correctly with default selec { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#0376C91A", - "borderColor": "#0376c9", + "backgroundColor": "#4459ff1a", + "borderColor": "#4459ff", "borderRadius": 20, "borderWidth": 1, "flexDirection": "row", @@ -143,12 +143,12 @@ exports[`SegmentedControl Multi-select mode renders correctly with default selec accessibilityRole="text" style={ { - "color": "#0376c9", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#4459ff", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -175,7 +175,7 @@ exports[`SegmentedControl Multi-select mode renders correctly with default selec "alignItems": "center", "alignSelf": "flex-start", "backgroundColor": "transparent", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 20, "borderWidth": 1, "flexDirection": "row", @@ -189,12 +189,12 @@ exports[`SegmentedControl Multi-select mode renders correctly with default selec accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -236,8 +236,8 @@ exports[`SegmentedControl Single-select mode renders correctly with default sele { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#0376C91A", - "borderColor": "#0376c9", + "backgroundColor": "#4459ff1a", + "borderColor": "#4459ff", "borderRadius": 20, "borderWidth": 1, "flexDirection": "row", @@ -251,12 +251,12 @@ exports[`SegmentedControl Single-select mode renders correctly with default sele accessibilityRole="text" style={ { - "color": "#0376c9", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#4459ff", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -283,7 +283,7 @@ exports[`SegmentedControl Single-select mode renders correctly with default sele "alignItems": "center", "alignSelf": "flex-start", "backgroundColor": "transparent", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 20, "borderWidth": 1, "flexDirection": "row", @@ -297,12 +297,12 @@ exports[`SegmentedControl Single-select mode renders correctly with default sele accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -329,7 +329,7 @@ exports[`SegmentedControl Single-select mode renders correctly with default sele "alignItems": "center", "alignSelf": "flex-start", "backgroundColor": "transparent", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 20, "borderWidth": 1, "flexDirection": "row", @@ -343,12 +343,12 @@ exports[`SegmentedControl Single-select mode renders correctly with default sele accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -375,7 +375,7 @@ exports[`SegmentedControl Single-select mode renders correctly with default sele "alignItems": "center", "alignSelf": "flex-start", "backgroundColor": "transparent", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 20, "borderWidth": 1, "flexDirection": "row", @@ -389,12 +389,12 @@ exports[`SegmentedControl Single-select mode renders correctly with default sele accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > diff --git a/app/component-library/components-temp/TagColored/__snapshots__/TagColored.test.tsx.snap b/app/component-library/components-temp/TagColored/__snapshots__/TagColored.test.tsx.snap index dbc580fb4b1..b7c90991ffc 100644 --- a/app/component-library/components-temp/TagColored/__snapshots__/TagColored.test.tsx.snap +++ b/app/component-library/components-temp/TagColored/__snapshots__/TagColored.test.tsx.snap @@ -6,7 +6,7 @@ exports[`TagColored should render TagColored 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#f2f4f6", + "backgroundColor": "#f3f5f9", "borderRadius": 4, "height": 20, "justifyContent": "center", @@ -19,12 +19,12 @@ exports[`TagColored should render TagColored 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 10, + "color": "#686e7d", + "fontFamily": "CentraNo1-Bold", + "fontSize": 12, "fontWeight": "bold", "letterSpacing": 0.25, - "lineHeight": 16, + "lineHeight": 20, "textTransform": "uppercase", } } diff --git a/app/component-library/components/Accordions/Accordion/foundation/AccordionHeader/__snapshots__/AccordionHeader.test.tsx.snap b/app/component-library/components/Accordions/Accordion/foundation/AccordionHeader/__snapshots__/AccordionHeader.test.tsx.snap index b325932ea89..b810802c075 100644 --- a/app/component-library/components/Accordions/Accordion/foundation/AccordionHeader/__snapshots__/AccordionHeader.test.tsx.snap +++ b/app/component-library/components/Accordions/Accordion/foundation/AccordionHeader/__snapshots__/AccordionHeader.test.tsx.snap @@ -17,7 +17,7 @@ exports[`AccordionHeader - Snapshot should render a rotated down Arrow if isExpa @@ -81,8 +81,8 @@ exports[`Banner should render correctly with a close button 1`] = ` @@ -162,7 +162,7 @@ exports[`Banner should render correctly with a close button 1`] = ` "alignItems": "center", "alignSelf": "flex-start", "backgroundColor": "transparent", - "borderColor": "#0376c9", + "borderColor": "#4459ff", "borderRadius": 0, "borderWidth": 1, "flexDirection": "row", @@ -176,12 +176,12 @@ exports[`Banner should render correctly with a close button 1`] = ` accessibilityRole="text" style={ { - "color": "#0376c9", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#4459ff", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -216,7 +216,7 @@ exports[`Banner should render correctly with a close button 1`] = ` testID="banner-close-button-icon" > @@ -282,9 +282,9 @@ exports[`Banner should render correctly with a start accessory 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "letterSpacing": 0, "lineHeight": 24, @@ -297,12 +297,12 @@ exports[`Banner should render correctly with a start accessory 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -316,8 +316,8 @@ exports[`Banner should render correctly with an action button 1`] = ` @@ -397,7 +397,7 @@ exports[`Banner should render correctly with an action button 1`] = ` "alignItems": "center", "alignSelf": "flex-start", "backgroundColor": "transparent", - "borderColor": "#0376c9", + "borderColor": "#4459ff", "borderRadius": 0, "borderWidth": 1, "flexDirection": "row", @@ -411,12 +411,12 @@ exports[`Banner should render correctly with an action button 1`] = ` accessibilityRole="text" style={ { - "color": "#0376c9", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#4459ff", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > diff --git a/app/component-library/components/Banners/Banner/variants/BannerAlert/__snapshots__/BannerAlert.test.tsx.snap b/app/component-library/components/Banners/Banner/variants/BannerAlert/__snapshots__/BannerAlert.test.tsx.snap index 64afd8569c0..842ea72d5b6 100644 --- a/app/component-library/components/Banners/Banner/variants/BannerAlert/__snapshots__/BannerAlert.test.tsx.snap +++ b/app/component-library/components/Banners/Banner/variants/BannerAlert/__snapshots__/BannerAlert.test.tsx.snap @@ -4,8 +4,8 @@ exports[`BannerAlert should render BannerAlert 1`] = ` @@ -81,12 +81,12 @@ exports[`BannerAlert should render BannerAlert 1`] = ` style={ { "backgroundColor": "transparent", - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } suppressHighlighting={true} @@ -95,12 +95,12 @@ exports[`BannerAlert should render BannerAlert 1`] = ` accessibilityRole="text" style={ { - "color": "#0376c9", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#4459ff", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -135,7 +135,7 @@ exports[`BannerAlert should render BannerAlert 1`] = ` testID="banner-close-button-icon" > @@ -87,12 +87,12 @@ exports[`BannerTip should render default settings correctly 1`] = ` style={ { "backgroundColor": "transparent", - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } suppressHighlighting={true} @@ -101,12 +101,12 @@ exports[`BannerTip should render default settings correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#0376c9", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#4459ff", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -141,7 +141,7 @@ exports[`BannerTip should render default settings correctly 1`] = ` testID="banner-close-button-icon" > @@ -63,7 +63,7 @@ exports[`BottomSheetFooter should render snapshot correctly 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 20, "flex": 1, "flexDirection": "row", @@ -81,11 +81,11 @@ exports[`BottomSheetFooter should render snapshot correctly 1`] = ` style={ { "color": "#ffffff", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > diff --git a/app/component-library/components/BottomSheets/BottomSheetHeader/__snapshots__/BottomSheetHeader.test.tsx.snap b/app/component-library/components/BottomSheets/BottomSheetHeader/__snapshots__/BottomSheetHeader.test.tsx.snap index 3842a123952..a14af1fadbd 100644 --- a/app/component-library/components/BottomSheets/BottomSheetHeader/__snapshots__/BottomSheetHeader.test.tsx.snap +++ b/app/component-library/components/BottomSheets/BottomSheetHeader/__snapshots__/BottomSheetHeader.test.tsx.snap @@ -38,8 +38,8 @@ exports[`BottomSheetHeader should render snapshot correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", + "color": "#121314", + "fontFamily": "CentraNo1-Bold", "fontSize": 16, "fontWeight": "700", "letterSpacing": 0, diff --git a/app/component-library/components/Buttons/Button/foundation/ButtonBase/__snapshots__/ButtonBase.test.tsx.snap b/app/component-library/components/Buttons/Button/foundation/ButtonBase/__snapshots__/ButtonBase.test.tsx.snap index acdab062c11..2540a3ee4b9 100644 --- a/app/component-library/components/Buttons/Button/foundation/ButtonBase/__snapshots__/ButtonBase.test.tsx.snap +++ b/app/component-library/components/Buttons/Button/foundation/ButtonBase/__snapshots__/ButtonBase.test.tsx.snap @@ -10,7 +10,7 @@ exports[`ButtonBase should render correctly 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#f2f4f6", + "backgroundColor": "#f3f5f9", "borderRadius": 20, "flexDirection": "row", "height": 40, @@ -33,7 +33,7 @@ exports[`ButtonBase should render correctly 1`] = ` accessibilityRole="none" style={ { - "color": "#141618", + "color": "#121314", } } variant="sBodyMDMedium" @@ -54,7 +54,7 @@ exports[`ButtonBase should render correctly when disabled 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#f2f4f6", + "backgroundColor": "#f3f5f9", "borderRadius": 20, "flexDirection": "row", "height": 40, @@ -78,7 +78,7 @@ exports[`ButtonBase should render correctly when disabled 1`] = ` accessibilityRole="none" style={ { - "color": "#141618", + "color": "#121314", } } variant="sBodyMDMedium" diff --git a/app/component-library/components/Buttons/Button/variants/ButtonLink/__snapshots__/ButtonLink.test.tsx.snap b/app/component-library/components/Buttons/Button/variants/ButtonLink/__snapshots__/ButtonLink.test.tsx.snap index d636f704af6..1790f3079b1 100644 --- a/app/component-library/components/Buttons/Button/variants/ButtonLink/__snapshots__/ButtonLink.test.tsx.snap +++ b/app/component-library/components/Buttons/Button/variants/ButtonLink/__snapshots__/ButtonLink.test.tsx.snap @@ -10,12 +10,12 @@ exports[`ButtonLink should render correctly 1`] = ` style={ { "backgroundColor": "transparent", - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } suppressHighlighting={true} @@ -24,12 +24,12 @@ exports[`ButtonLink should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#0376c9", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#4459ff", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > diff --git a/app/component-library/components/Buttons/Button/variants/ButtonPrimary/__snapshots__/ButtonPrimary.test.tsx.snap b/app/component-library/components/Buttons/Button/variants/ButtonPrimary/__snapshots__/ButtonPrimary.test.tsx.snap index 74f4e35aa52..47fc1900553 100644 --- a/app/component-library/components/Buttons/Button/variants/ButtonPrimary/__snapshots__/ButtonPrimary.test.tsx.snap +++ b/app/component-library/components/Buttons/Button/variants/ButtonPrimary/__snapshots__/ButtonPrimary.test.tsx.snap @@ -13,7 +13,7 @@ exports[`ButtonPrimary render matches latest snapshot 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 20, "flexDirection": "row", "height": 40, @@ -40,11 +40,11 @@ exports[`ButtonPrimary render matches latest snapshot 1`] = ` style={ { "color": "#ffffff", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > diff --git a/app/component-library/components/Buttons/Button/variants/ButtonSecondary/__snapshots__/ButtonSecondary.test.tsx.snap b/app/component-library/components/Buttons/Button/variants/ButtonSecondary/__snapshots__/ButtonSecondary.test.tsx.snap index d35a16c686b..5c3962554e4 100644 --- a/app/component-library/components/Buttons/Button/variants/ButtonSecondary/__snapshots__/ButtonSecondary.test.tsx.snap +++ b/app/component-library/components/Buttons/Button/variants/ButtonSecondary/__snapshots__/ButtonSecondary.test.tsx.snap @@ -13,7 +13,7 @@ exports[`ButtonSecondary should render correctly 1`] = ` "alignItems": "center", "alignSelf": "flex-start", "backgroundColor": "transparent", - "borderColor": "#0376c9", + "borderColor": "#4459ff", "borderRadius": 20, "borderWidth": 1, "flexDirection": "row", @@ -24,7 +24,7 @@ exports[`ButtonSecondary should render correctly 1`] = ` } > diff --git a/app/component-library/components/Buttons/ButtonIcon/__snapshots__/ButtonIcon.test.tsx.snap b/app/component-library/components/Buttons/ButtonIcon/__snapshots__/ButtonIcon.test.tsx.snap index 14d64bfb684..3ea0f3c1869 100644 --- a/app/component-library/components/Buttons/ButtonIcon/__snapshots__/ButtonIcon.test.tsx.snap +++ b/app/component-library/components/Buttons/ButtonIcon/__snapshots__/ButtonIcon.test.tsx.snap @@ -20,7 +20,7 @@ exports[`ButtonIcon should render correctly 1`] = ` } > @@ -219,12 +219,12 @@ exports[`Cell should render CellDisplay given the type Display 1`] = ` numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -234,7 +234,7 @@ exports[`Cell should render CellDisplay given the type Display 1`] = ` style={ { "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 10, "borderWidth": 1, "height": 24, @@ -248,12 +248,12 @@ exports[`Cell should render CellDisplay given the type Display 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -313,7 +313,7 @@ exports[`Cell should render CellMultiSelect given the type MultiSelect 1`] = ` { "alignItems": "center", "backgroundColor": "#ffffff", - "borderColor": "#141618", + "borderColor": "#121314", "borderRadius": 4, "borderWidth": 2, "height": 20, @@ -495,8 +495,8 @@ exports[`Cell should render CellMultiSelect given the type MultiSelect 1`] = ` numberOfLines={1} style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", + "color": "#121314", + "fontFamily": "CentraNo1-Book", "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, @@ -512,12 +512,12 @@ exports[`Cell should render CellMultiSelect given the type MultiSelect 1`] = ` numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -528,12 +528,12 @@ exports[`Cell should render CellMultiSelect given the type MultiSelect 1`] = ` numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -543,7 +543,7 @@ exports[`Cell should render CellMultiSelect given the type MultiSelect 1`] = ` style={ { "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 10, "borderWidth": 1, "height": 24, @@ -557,12 +557,12 @@ exports[`Cell should render CellMultiSelect given the type MultiSelect 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -768,8 +768,8 @@ exports[`Cell should render CellSelect given the type Select 1`] = ` numberOfLines={1} style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", + "color": "#121314", + "fontFamily": "CentraNo1-Book", "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, @@ -785,12 +785,12 @@ exports[`Cell should render CellSelect given the type Select 1`] = ` numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -801,12 +801,12 @@ exports[`Cell should render CellSelect given the type Select 1`] = ` numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -816,7 +816,7 @@ exports[`Cell should render CellSelect given the type Select 1`] = ` style={ { "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 10, "borderWidth": 1, "height": 24, @@ -830,12 +830,12 @@ exports[`Cell should render CellSelect given the type Select 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > diff --git a/app/component-library/components/Cells/Cell/foundation/CellBase/__snapshots__/CellBase.test.tsx.snap b/app/component-library/components/Cells/Cell/foundation/CellBase/__snapshots__/CellBase.test.tsx.snap index 76c35ea6303..570d6f5a49f 100644 --- a/app/component-library/components/Cells/Cell/foundation/CellBase/__snapshots__/CellBase.test.tsx.snap +++ b/app/component-library/components/Cells/Cell/foundation/CellBase/__snapshots__/CellBase.test.tsx.snap @@ -163,8 +163,8 @@ exports[`CellBase should render default settings correctly 1`] = ` numberOfLines={1} style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", + "color": "#121314", + "fontFamily": "CentraNo1-Book", "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, @@ -180,12 +180,12 @@ exports[`CellBase should render default settings correctly 1`] = ` numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -196,12 +196,12 @@ exports[`CellBase should render default settings correctly 1`] = ` numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -211,7 +211,7 @@ exports[`CellBase should render default settings correctly 1`] = ` style={ { "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 10, "borderWidth": 1, "height": 24, @@ -225,12 +225,12 @@ exports[`CellBase should render default settings correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > diff --git a/app/component-library/components/Cells/Cell/variants/CellDisplay/__snapshots__/CellDisplay.test.tsx.snap b/app/component-library/components/Cells/Cell/variants/CellDisplay/__snapshots__/CellDisplay.test.tsx.snap index 77968e14c29..5df6dfb7a1b 100644 --- a/app/component-library/components/Cells/Cell/variants/CellDisplay/__snapshots__/CellDisplay.test.tsx.snap +++ b/app/component-library/components/Cells/Cell/variants/CellDisplay/__snapshots__/CellDisplay.test.tsx.snap @@ -13,7 +13,7 @@ exports[`CellDisplay should render default settings correctly 1`] = ` style={ { "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 4, "borderWidth": 1, "padding": 16, @@ -186,8 +186,8 @@ exports[`CellDisplay should render default settings correctly 1`] = ` numberOfLines={1} style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", + "color": "#121314", + "fontFamily": "CentraNo1-Book", "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, @@ -203,12 +203,12 @@ exports[`CellDisplay should render default settings correctly 1`] = ` numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -219,12 +219,12 @@ exports[`CellDisplay should render default settings correctly 1`] = ` numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -234,7 +234,7 @@ exports[`CellDisplay should render default settings correctly 1`] = ` style={ { "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 10, "borderWidth": 1, "height": 24, @@ -248,12 +248,12 @@ exports[`CellDisplay should render default settings correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > diff --git a/app/component-library/components/Cells/Cell/variants/CellMultiSelect/__snapshots__/CellMultiSelect.test.tsx.snap b/app/component-library/components/Cells/Cell/variants/CellMultiSelect/__snapshots__/CellMultiSelect.test.tsx.snap index 28b4981d316..e425d5a31ad 100644 --- a/app/component-library/components/Cells/Cell/variants/CellMultiSelect/__snapshots__/CellMultiSelect.test.tsx.snap +++ b/app/component-library/components/Cells/Cell/variants/CellMultiSelect/__snapshots__/CellMultiSelect.test.tsx.snap @@ -48,7 +48,7 @@ exports[`CellMultiSelect should render default settings correctly 1`] = ` { "alignItems": "center", "backgroundColor": "#ffffff", - "borderColor": "#141618", + "borderColor": "#121314", "borderRadius": 4, "borderWidth": 2, "height": 20, @@ -230,8 +230,8 @@ exports[`CellMultiSelect should render default settings correctly 1`] = ` numberOfLines={1} style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", + "color": "#121314", + "fontFamily": "CentraNo1-Book", "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, @@ -247,12 +247,12 @@ exports[`CellMultiSelect should render default settings correctly 1`] = ` numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -263,12 +263,12 @@ exports[`CellMultiSelect should render default settings correctly 1`] = ` numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -278,7 +278,7 @@ exports[`CellMultiSelect should render default settings correctly 1`] = ` style={ { "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 10, "borderWidth": 1, "height": 24, @@ -292,12 +292,12 @@ exports[`CellMultiSelect should render default settings correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > diff --git a/app/component-library/components/Cells/Cell/variants/CellSelect/__snapshots__/CellSelect.test.tsx.snap b/app/component-library/components/Cells/Cell/variants/CellSelect/__snapshots__/CellSelect.test.tsx.snap index 42eff249285..a3e38d0a377 100644 --- a/app/component-library/components/Cells/Cell/variants/CellSelect/__snapshots__/CellSelect.test.tsx.snap +++ b/app/component-library/components/Cells/Cell/variants/CellSelect/__snapshots__/CellSelect.test.tsx.snap @@ -192,8 +192,8 @@ exports[`CellSelect should render default settings correctly 1`] = ` numberOfLines={1} style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", + "color": "#121314", + "fontFamily": "CentraNo1-Book", "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, @@ -209,12 +209,12 @@ exports[`CellSelect should render default settings correctly 1`] = ` numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -225,12 +225,12 @@ exports[`CellSelect should render default settings correctly 1`] = ` numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -240,7 +240,7 @@ exports[`CellSelect should render default settings correctly 1`] = ` style={ { "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 10, "borderWidth": 1, "height": 24, @@ -254,12 +254,12 @@ exports[`CellSelect should render default settings correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > diff --git a/app/component-library/components/Checkbox/Checkbox.test.tsx b/app/component-library/components/Checkbox/Checkbox.test.tsx index c36c674d940..391337ed84e 100644 --- a/app/component-library/components/Checkbox/Checkbox.test.tsx +++ b/app/component-library/components/Checkbox/Checkbox.test.tsx @@ -3,9 +3,7 @@ import React from 'react'; import { render } from '@testing-library/react-native'; // External dependencies. -import Text, { TextVariant } from '../Texts/Text'; -import { mockTheme } from '../../../util/theme'; -import { getFontStyleVariant, FontWeight } from '../Texts/Text/Text.utils'; +import Text, { TextVariant, getFontFamily } from '../Texts/Text'; // Internal dependencies. import Checkbox from './Checkbox'; @@ -48,11 +46,7 @@ describe('Checkbox', () => { it('should render Checkbox with the right text variant if typeof label === string', () => { const { getByRole } = render(); - const fontFamily = getFontStyleVariant( - mockTheme.typography[DEFAULT_CHECKBOX_LABEL_TEXTVARIANT] - .fontWeight as FontWeight, - 'normal', - ); + const fontFamily = getFontFamily(DEFAULT_CHECKBOX_LABEL_TEXTVARIANT); expect(getByRole('text').props.style.fontFamily).toBe(fontFamily); }); @@ -63,10 +57,7 @@ describe('Checkbox', () => { label={Sample Checkbox Label} />, ); - const fontFamily = getFontStyleVariant( - mockTheme.typography[testTextVariant].fontWeight as FontWeight, - 'normal', - ); + const fontFamily = getFontFamily(testTextVariant); expect(getByRole('text').props.style.fontFamily).toBe(fontFamily); }); }); diff --git a/app/component-library/components/Checkbox/__snapshots__/Checkbox.test.tsx.snap b/app/component-library/components/Checkbox/__snapshots__/Checkbox.test.tsx.snap index 18c986748e8..f01b080f84c 100644 --- a/app/component-library/components/Checkbox/__snapshots__/Checkbox.test.tsx.snap +++ b/app/component-library/components/Checkbox/__snapshots__/Checkbox.test.tsx.snap @@ -18,7 +18,7 @@ exports[`Checkbox should render correctly 1`] = ` { "alignItems": "center", "backgroundColor": "#ffffff", - "borderColor": "#141618", + "borderColor": "#121314", "borderRadius": 4, "borderWidth": 2, "height": 20, diff --git a/app/component-library/components/Form/TextField/__snapshots__/TextField.test.tsx.snap b/app/component-library/components/Form/TextField/__snapshots__/TextField.test.tsx.snap index dfe8245cb0b..3e597e4e167 100644 --- a/app/component-library/components/Form/TextField/__snapshots__/TextField.test.tsx.snap +++ b/app/component-library/components/Form/TextField/__snapshots__/TextField.test.tsx.snap @@ -6,7 +6,7 @@ exports[`TextField should render default settings correctly 1`] = ` { "alignItems": "center", "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 8, "borderWidth": 1, "flexDirection": "row", diff --git a/app/component-library/components/Form/TextField/foundation/Input/Input.styles.ts b/app/component-library/components/Form/TextField/foundation/Input/Input.styles.ts index 5df3c92c699..682436a6e8e 100644 --- a/app/component-library/components/Form/TextField/foundation/Input/Input.styles.ts +++ b/app/component-library/components/Form/TextField/foundation/Input/Input.styles.ts @@ -4,6 +4,7 @@ import { StyleSheet, TextStyle } from 'react-native'; // External dependencies. import { Theme } from '../../../../../../util/theme/models'; import { colors } from '../../../../../../styles/common'; +import { getFontFamily } from '../../../../Texts/Text/'; // Internal dependencies import { InputStyleSheetVars } from './Input.types'; @@ -40,7 +41,7 @@ const styleSheet = (params: { theme: Theme; vars: InputStyleSheetVars }) => { height: 24, ...stateObj, paddingVertical: 0, - fontFamily: theme.typography[textVariant].fontFamily, + fontFamily: getFontFamily(textVariant), fontWeight: theme.typography[textVariant].fontWeight, fontSize: theme.typography[textVariant].fontSize, letterSpacing: theme.typography[textVariant].letterSpacing, diff --git a/app/component-library/components/Form/TextField/foundation/Input/__snapshots__/Input.test.tsx.snap b/app/component-library/components/Form/TextField/foundation/Input/__snapshots__/Input.test.tsx.snap index fd6fedfeaa4..3497fb265be 100644 --- a/app/component-library/components/Form/TextField/foundation/Input/__snapshots__/Input.test.tsx.snap +++ b/app/component-library/components/Form/TextField/foundation/Input/__snapshots__/Input.test.tsx.snap @@ -9,11 +9,11 @@ exports[`Input should render correctly 1`] = ` style={ { "backgroundColor": "#ffffff", - "borderColor": "#0376c9", + "borderColor": "#4459ff", "borderWidth": 1, - "color": "#141618", - "fontFamily": "Euclid Circular B", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "height": 24, "letterSpacing": 0, diff --git a/app/component-library/components/HeaderBase/HeaderBase.test.tsx b/app/component-library/components/HeaderBase/HeaderBase.test.tsx index a6414e75bf2..44466019bdd 100644 --- a/app/component-library/components/HeaderBase/HeaderBase.test.tsx +++ b/app/component-library/components/HeaderBase/HeaderBase.test.tsx @@ -4,9 +4,7 @@ import { render } from '@testing-library/react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; // External dependencies. -import Text, { TextVariant } from '../Texts/Text'; -import { mockTheme } from '../../../util/theme'; -import { getFontStyleVariant, FontWeight } from '../Texts/Text/Text.utils'; +import Text, { TextVariant, getFontFamily } from '../Texts/Text'; // Internal dependencies. import HeaderBase from './HeaderBase'; @@ -40,11 +38,7 @@ describe('HeaderBase', () => { const { getByRole } = render( Sample HeaderBase Title, ); - const fontFamily = getFontStyleVariant( - mockTheme.typography[DEFAULT_HEADERBASE_TITLE_TEXTVARIANT] - .fontWeight as FontWeight, - 'normal', - ); + const fontFamily = getFontFamily(DEFAULT_HEADERBASE_TITLE_TEXTVARIANT); expect(getByRole('text').props.style.fontFamily).toBe(fontFamily); }); @@ -58,10 +52,7 @@ describe('HeaderBase', () => { , ); - const fontFamily = getFontStyleVariant( - mockTheme.typography[testTextVariant].fontWeight as FontWeight, - 'normal', - ); + const fontFamily = getFontFamily(testTextVariant); expect(getByRole('text').props.style.fontFamily).toBe(fontFamily); }); diff --git a/app/component-library/components/HeaderBase/__snapshots__/HeaderBase.test.tsx.snap b/app/component-library/components/HeaderBase/__snapshots__/HeaderBase.test.tsx.snap index f08525a62d2..814c204f6e8 100644 --- a/app/component-library/components/HeaderBase/__snapshots__/HeaderBase.test.tsx.snap +++ b/app/component-library/components/HeaderBase/__snapshots__/HeaderBase.test.tsx.snap @@ -37,8 +37,8 @@ exports[`HeaderBase should render snapshot correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", + "color": "#121314", + "fontFamily": "CentraNo1-Bold", "fontSize": 16, "fontWeight": "700", "letterSpacing": 0, diff --git a/app/component-library/components/Icons/Icon/__snapshots__/Icon.test.tsx.snap b/app/component-library/components/Icons/Icon/__snapshots__/Icon.test.tsx.snap index d56be0cd7c4..218b43ecde0 100644 --- a/app/component-library/components/Icons/Icon/__snapshots__/Icon.test.tsx.snap +++ b/app/component-library/components/Icons/Icon/__snapshots__/Icon.test.tsx.snap @@ -2,7 +2,7 @@ exports[`Icon renders correctly 1`] = ` { headerText: { color: colors.text.default, ...(typography.sHeadingMD as TextStyle), + fontFamily: getFontFamily(TextVariant.HeadingMD), textAlign: 'center', marginBottom: 16, }, @@ -41,6 +43,7 @@ const styleSheet = (params: { theme: Theme }) => { flex: 1, color: colors.text.default, ...(typography.sBodyMDBold as TextStyle), + fontFamily: getFontFamily(TextVariant.BodyMDBold), }, confirmButton: { marginTop: 16, @@ -66,6 +69,7 @@ const styleSheet = (params: { theme: Theme }) => { textAlign: 'center', color: colors.text.alternative, ...(typography.sBodySM as TextStyle), + fontFamily: getFontFamily(TextVariant.BodySM), }, }); }; diff --git a/app/component-library/components/Navigation/TabBar/__snapshots__/TabBar.test.tsx.snap b/app/component-library/components/Navigation/TabBar/__snapshots__/TabBar.test.tsx.snap index 1cd1fd3f748..e272b3aaab5 100644 --- a/app/component-library/components/Navigation/TabBar/__snapshots__/TabBar.test.tsx.snap +++ b/app/component-library/components/Navigation/TabBar/__snapshots__/TabBar.test.tsx.snap @@ -7,7 +7,7 @@ exports[`TabBar renders correctly 1`] = ` { "backgroundColor": "#ffffff", "flexBasis": 1, - "shadowColor": "#00000099", + "shadowColor": "#00000066", "shadowOffset": { "height": 4, "width": 0, @@ -53,7 +53,7 @@ exports[`TabBar renders correctly 1`] = ` } > { const { getByRole } = render( , ); - const fontFamily = getFontStyleVariant( - mockTheme.typography[DEFAULT_RADIOBUTTON_LABEL_TEXTVARIANT] - .fontWeight as FontWeight, - 'normal', - ); + const fontFamily = getFontFamily(DEFAULT_RADIOBUTTON_LABEL_TEXTVARIANT); expect(getByRole('text').props.style.fontFamily).toBe(fontFamily); }); @@ -56,10 +50,7 @@ describe('RadioButton', () => { />, ); - const fontFamily = getFontStyleVariant( - mockTheme.typography[testTextVariant].fontWeight as FontWeight, - 'normal', - ); + const fontFamily = getFontFamily(testTextVariant); expect(getByRole('text').props.style.fontFamily).toBe(fontFamily); }); }); diff --git a/app/component-library/components/RadioButton/__snapshots__/RadioButton.test.tsx.snap b/app/component-library/components/RadioButton/__snapshots__/RadioButton.test.tsx.snap index e6893885733..e6644f8f5bb 100644 --- a/app/component-library/components/RadioButton/__snapshots__/RadioButton.test.tsx.snap +++ b/app/component-library/components/RadioButton/__snapshots__/RadioButton.test.tsx.snap @@ -18,7 +18,7 @@ exports[`RadioButton should render correctly 1`] = ` { "alignItems": "center", "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 99, "borderWidth": 2, "height": 20, diff --git a/app/component-library/components/Select/SelectButton/__snapshots__/SelectButton.test.tsx.snap b/app/component-library/components/Select/SelectButton/__snapshots__/SelectButton.test.tsx.snap index ac0e41bda72..4f47f7e8350 100644 --- a/app/component-library/components/Select/SelectButton/__snapshots__/SelectButton.test.tsx.snap +++ b/app/component-library/components/Select/SelectButton/__snapshots__/SelectButton.test.tsx.snap @@ -8,7 +8,7 @@ exports[`SelectButton should render snapshot correctly 1`] = ` { "alignItems": "center", "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 8, "borderWidth": 1, "flexDirection": "row", @@ -209,12 +209,12 @@ exports[`SelectButton should render snapshot correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -225,12 +225,12 @@ exports[`SelectButton should render snapshot correctly 1`] = ` numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > @@ -241,7 +241,7 @@ exports[`SelectButton should render snapshot correctly 1`] = ` @@ -216,12 +216,12 @@ exports[`SelectButtonBase should render snapshot correctly 1`] = ` numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > @@ -232,7 +232,7 @@ exports[`SelectButtonBase should render snapshot correctly 1`] = ` @@ -234,12 +234,12 @@ exports[`SelectOption should render snapshot correctly 1`] = ` numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > diff --git a/app/component-library/components/Select/SelectValue/SelectValue.test.tsx b/app/component-library/components/Select/SelectValue/SelectValue.test.tsx index 5a8b681ffc4..5eef64ad2a3 100644 --- a/app/component-library/components/Select/SelectValue/SelectValue.test.tsx +++ b/app/component-library/components/Select/SelectValue/SelectValue.test.tsx @@ -3,8 +3,7 @@ import React from 'react'; import { render } from '@testing-library/react-native'; // External dependencies. -import { mockTheme } from '../../../../util/theme'; -import { getFontStyleVariant, FontWeight } from '../../Texts/Text/Text.utils'; +import { getFontFamily } from '../../Texts/Text/'; // Internal dependencies. import SelectValue from './SelectValue'; @@ -24,11 +23,7 @@ describe('SelectValue', () => { , ); - const fontFamily = getFontStyleVariant( - mockTheme.typography[DEFAULT_SELECTVALUE_LABEL_TEXTVARIANT] - .fontWeight as FontWeight, - 'normal', - ); + const fontFamily = getFontFamily(DEFAULT_SELECTVALUE_LABEL_TEXTVARIANT); expect(getByRole('text').props.style.fontFamily).toBe(fontFamily); }); @@ -37,10 +32,8 @@ describe('SelectValue', () => { , ); - const fontFamily = getFontStyleVariant( - mockTheme.typography[DEFAULT_SELECTVALUE_DESCRIPTION_TEXTVARIANT] - .fontWeight as FontWeight, - 'normal', + const fontFamily = getFontFamily( + DEFAULT_SELECTVALUE_DESCRIPTION_TEXTVARIANT, ); expect(getByRole('text').props.style.fontFamily).toBe(fontFamily); diff --git a/app/component-library/components/Select/SelectValue/__snapshots__/SelectValue.test.tsx.snap b/app/component-library/components/Select/SelectValue/__snapshots__/SelectValue.test.tsx.snap index 9db4ae456c2..8491c6414a2 100644 --- a/app/component-library/components/Select/SelectValue/__snapshots__/SelectValue.test.tsx.snap +++ b/app/component-library/components/Select/SelectValue/__snapshots__/SelectValue.test.tsx.snap @@ -189,12 +189,12 @@ exports[`SelectValue should render snapshot correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -205,12 +205,12 @@ exports[`SelectValue should render snapshot correctly 1`] = ` numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > diff --git a/app/component-library/components/Skeleton/__snapshots__/Skeleton.test.tsx.snap b/app/component-library/components/Skeleton/__snapshots__/Skeleton.test.tsx.snap index 54717348125..a7ba18b4d6e 100644 --- a/app/component-library/components/Skeleton/__snapshots__/Skeleton.test.tsx.snap +++ b/app/component-library/components/Skeleton/__snapshots__/Skeleton.test.tsx.snap @@ -14,7 +14,7 @@ exports[`Skeleton should match snapshot 1`] = ` pointerEvents="none" style={ { - "backgroundColor": "#6a737d", + "backgroundColor": "#686e7d", "borderRadius": 4, "bottom": 0, "left": 0, diff --git a/app/component-library/components/Tags/Tag/__snapshots__/Tag.test.tsx.snap b/app/component-library/components/Tags/Tag/__snapshots__/Tag.test.tsx.snap index f34996cc100..5767b6a30cb 100644 --- a/app/component-library/components/Tags/Tag/__snapshots__/Tag.test.tsx.snap +++ b/app/component-library/components/Tags/Tag/__snapshots__/Tag.test.tsx.snap @@ -5,7 +5,7 @@ exports[`Tag should render correctly 1`] = ` style={ { "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 10, "borderWidth": 1, "height": 24, @@ -18,12 +18,12 @@ exports[`Tag should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > diff --git a/app/component-library/components/Tags/TagUrl/__snapshots__/TagUrl.test.tsx.snap b/app/component-library/components/Tags/TagUrl/__snapshots__/TagUrl.test.tsx.snap index 3957d9e208c..77043ee349a 100644 --- a/app/component-library/components/Tags/TagUrl/__snapshots__/TagUrl.test.tsx.snap +++ b/app/component-library/components/Tags/TagUrl/__snapshots__/TagUrl.test.tsx.snap @@ -7,7 +7,7 @@ exports[`TagUrl should render correctly 1`] = ` "alignItems": "center", "alignSelf": "center", "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 99, "borderWidth": 1, "flexDirection": "row", @@ -36,7 +36,7 @@ exports[`TagUrl should render correctly 1`] = ` diff --git a/app/component-library/components/Texts/Text/Text.stories.tsx b/app/component-library/components/Texts/Text/Text.stories.tsx index c093a45843f..80263f92133 100644 --- a/app/component-library/components/Texts/Text/Text.stories.tsx +++ b/app/component-library/components/Texts/Text/Text.stories.tsx @@ -26,9 +26,6 @@ const TextMeta = { }, defaultValue: SAMPLE_TEXT_PROPS.color, }, - isBrandEvolution: { - control: { type: 'boolean' }, - }, }, }; export default TextMeta; @@ -68,27 +65,3 @@ TextVariants.argTypes = { TextVariants.args = { color: SAMPLE_TEXT_PROPS.color, }; - -export const TextVariantsBrandEvolution = ( - args: React.JSX.IntrinsicAttributes & - TextProps & { children?: React.ReactNode | undefined }, -) => ( - <> - - Brand Evolution - - {Object.values(TextVariant).map((variant) => ( - - {variant} - - ))} - -); -TextVariantsBrandEvolution.argTypes = { - variant: { control: false }, - children: { control: false }, - isBrandEvolution: { control: false }, -}; -TextVariantsBrandEvolution.args = { - color: SAMPLE_TEXT_PROPS.color, -}; diff --git a/app/component-library/components/Texts/Text/Text.styles.ts b/app/component-library/components/Texts/Text/Text.styles.ts index 35abb7e32ec..df839589edd 100644 --- a/app/component-library/components/Texts/Text/Text.styles.ts +++ b/app/component-library/components/Texts/Text/Text.styles.ts @@ -6,10 +6,7 @@ import { Theme } from '../../../../util/theme/models'; // Internal dependencies. import { TextColor, TextVariant } from './Text.types'; -import { - getFontStyleVariant, - getFontStyleVariantForBrandEvolution, -} from './Text.utils'; +import { getFontFamily } from './Text.utils'; /** * Style sheet function for Text component. @@ -23,7 +20,7 @@ import { // eslint-disable-next-line @typescript-eslint/no-explicit-any const styleSheet = (params: { theme: Theme; vars: any }) => { const { theme, vars } = params; - const { variant, style, color, isBrandEvolution } = vars; + const { variant, style, color } = vars; let textColor; switch (color) { @@ -69,12 +66,8 @@ const styleSheet = (params: { theme: Theme; vars: any }) => { const fontObject = { ...variantObject, color: textColor, - fontFamily: isBrandEvolution - ? getFontStyleVariantForBrandEvolution(variant) - : getFontStyleVariant(finalFontWeight, style?.fontStyle), - ...(!isBrandEvolution && { - fontWeight: finalFontWeight, - }), + fontFamily: getFontFamily(variant, style?.fontWeight, style?.fontStyle), + fontWeight: finalFontWeight, }; return StyleSheet.create({ diff --git a/app/component-library/components/Texts/Text/Text.test.tsx b/app/component-library/components/Texts/Text/Text.test.tsx index 3ce7e975c99..93ca101d864 100644 --- a/app/component-library/components/Texts/Text/Text.test.tsx +++ b/app/component-library/components/Texts/Text/Text.test.tsx @@ -8,7 +8,7 @@ import { mockTheme } from '../../../../util/theme'; // Internal dependencies import Text from './Text'; import { SAMPLE_TEXT_PROPS, DEFAULT_TEXT_VARIANT } from './Text.constants'; -import { getFontStyleVariant, FontWeight } from './Text.utils'; +import { getFontFamily } from './Text.utils'; describe('Text', () => { it('should render correctly', () => { @@ -18,10 +18,7 @@ describe('Text', () => { it('should render the correct fontFamily', () => { const { getByRole } = render(); - const fontFamily = getFontStyleVariant( - mockTheme.typography[DEFAULT_TEXT_VARIANT].fontWeight as FontWeight, - 'normal', - ); + const fontFamily = getFontFamily(DEFAULT_TEXT_VARIANT); expect(getByRole('text').props.style.fontFamily).toBe(fontFamily); }); diff --git a/app/component-library/components/Texts/Text/Text.tsx b/app/component-library/components/Texts/Text/Text.tsx index d6f0d4cc5f3..88204141c59 100644 --- a/app/component-library/components/Texts/Text/Text.tsx +++ b/app/component-library/components/Texts/Text/Text.tsx @@ -17,14 +17,12 @@ const Text: React.FC = ({ color = DEFAULT_TEXT_COLOR, style, children, - isBrandEvolution = false, ...props }) => { const { styles } = useStyles(styleSheet, { variant, style, color, - isBrandEvolution, }); return ( diff --git a/app/component-library/components/Texts/Text/Text.types.ts b/app/component-library/components/Texts/Text/Text.types.ts index 5f3e1ee3810..e32d7daf306 100644 --- a/app/component-library/components/Texts/Text/Text.types.ts +++ b/app/component-library/components/Texts/Text/Text.types.ts @@ -31,7 +31,7 @@ export enum TextColor { Alternative = 'Alternative', Muted = 'Muted', Primary = 'Primary', - PrimaryAlternative = 'Primary', + PrimaryAlternative = 'PrimaryAlternative', Success = 'Success', Error = 'Error', ErrorAlternative = 'ErrorAlternative', @@ -39,6 +39,20 @@ export enum TextColor { Info = 'Info', } +export type FontWeight = + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'normal' + | 'bold'; +export type FontStyle = 'normal' | 'italic'; + /** * Text component props. */ @@ -56,8 +70,4 @@ export interface TextProps extends RNTextProps { * Optional prop to add color to text. */ color?: TextColor | string; - /** - * Temporary prop to enable brand evolution fonts - */ - isBrandEvolution?: boolean; } diff --git a/app/component-library/components/Texts/Text/Text.utils.ts b/app/component-library/components/Texts/Text/Text.utils.ts index 3e39ff39473..4406fd65d9f 100644 --- a/app/component-library/components/Texts/Text/Text.utils.ts +++ b/app/component-library/components/Texts/Text/Text.utils.ts @@ -1,65 +1,30 @@ -import { TextVariant } from './Text.types'; +import { typography } from '@metamask/design-tokens'; +import { FontWeight, FontStyle, TextVariant } from './Text.types'; -type FontFamilyByTextVariant = { - [key in TextVariant]: string; -}; - -export type FontWeight = - | '100' - | '200' - | '300' - | '400' - | '500' - | '600' - | '700' - | '800' - | '900' - | 'normal' - | 'bold'; -type FontStyle = 'normal' | 'italic'; - -export const getFontStyleVariant = ( - fontWeight: FontWeight = '400', - fontStyle: FontStyle = 'normal', +export const getFontFamily = ( + variant: TextVariant, + fontWeight?: FontWeight, + fontStyle?: FontStyle, ): string => { - const weightMap: { [key in FontWeight]: string } = { - '100': 'Regular', - '200': 'Regular', - '300': 'Regular', - '400': 'Regular', + const resolvedWeight = fontWeight ?? typography[variant].fontWeight; + const resolvedStyle = fontStyle ?? 'normal'; + + const weightToFontSuffix: Record = { + '100': 'Book', + '200': 'Book', + '300': 'Book', + '400': 'Book', '500': 'Medium', '600': 'Medium', '700': 'Bold', '800': 'Bold', '900': 'Bold', - normal: 'Regular', + normal: 'Book', bold: 'Bold', }; - const styleSuffix = fontStyle === 'italic' ? 'Italic' : ''; - - const fontSuffix = weightMap[fontWeight]; + const fontSuffix = weightToFontSuffix[resolvedWeight as FontWeight]; + const italicSuffix = resolvedStyle === 'italic' ? 'Italic' : ''; - return `EuclidCircularB-${fontSuffix}${styleSuffix}`; + return `CentraNo1-${fontSuffix}${italicSuffix}`; }; - -export const FONTFAMILY_BY_TEXTVARIANT: FontFamilyByTextVariant = { - [TextVariant.DisplayMD]: 'MMSans-Regular', - [TextVariant.HeadingLG]: 'MMSans-Regular', - [TextVariant.HeadingMD]: 'MMSans-Regular', - [TextVariant.HeadingSMRegular]: 'MMSans-Regular', - [TextVariant.HeadingSM]: 'MMSans-Regular', - [TextVariant.BodyLGMedium]: 'CentraNo1-Medium', - [TextVariant.BodyMD]: 'CentraNo1-Book', - [TextVariant.BodyMDMedium]: 'CentraNo1-Medium', - [TextVariant.BodyMDBold]: 'CentraNo1-Bold', - [TextVariant.BodySM]: 'CentraNo1-Book', - [TextVariant.BodySMMedium]: 'CentraNo1-Medium', - [TextVariant.BodySMBold]: 'CentraNo1-Bold', - [TextVariant.BodyXS]: 'CentraNo1-Book', - [TextVariant.BodyXSMedium]: 'CentraNo1-Medium', -}; - -export const getFontStyleVariantForBrandEvolution = ( - variant: TextVariant, -): string => FONTFAMILY_BY_TEXTVARIANT[variant]; diff --git a/app/component-library/components/Texts/Text/__snapshots__/Text.test.tsx.snap b/app/component-library/components/Texts/Text/__snapshots__/Text.test.tsx.snap index c30731c92e6..b7b64dac8df 100644 --- a/app/component-library/components/Texts/Text/__snapshots__/Text.test.tsx.snap +++ b/app/component-library/components/Texts/Text/__snapshots__/Text.test.tsx.snap @@ -5,12 +5,12 @@ exports[`Text should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > diff --git a/app/component-library/components/Texts/Text/index.ts b/app/component-library/components/Texts/Text/index.ts index 4ec1031324b..13539cbfad5 100644 --- a/app/component-library/components/Texts/Text/index.ts +++ b/app/component-library/components/Texts/Text/index.ts @@ -1,2 +1,4 @@ export { default } from './Text'; export { TextVariant, TextColor } from './Text.types'; +export type { FontStyle, FontWeight } from './Text.types'; +export { getFontFamily } from './Text.utils'; diff --git a/app/component-library/components/Texts/TextWithPrefixIcon/__snapshots__/TextWithPrefixIcon.test.tsx.snap b/app/component-library/components/Texts/TextWithPrefixIcon/__snapshots__/TextWithPrefixIcon.test.tsx.snap index 33dce582122..98020af3bf7 100644 --- a/app/component-library/components/Texts/TextWithPrefixIcon/__snapshots__/TextWithPrefixIcon.test.tsx.snap +++ b/app/component-library/components/Texts/TextWithPrefixIcon/__snapshots__/TextWithPrefixIcon.test.tsx.snap @@ -11,7 +11,7 @@ exports[`TextWithPrefixIcon - Snapshot should render default settings correctly testID="text-with-prefix-icon" > diff --git a/app/components/Approvals/ApprovalModal/ApprovalModal.tsx b/app/components/Approvals/ApprovalModal/ApprovalModal.tsx index 8b7391424d5..ef31ae4a922 100644 --- a/app/components/Approvals/ApprovalModal/ApprovalModal.tsx +++ b/app/components/Approvals/ApprovalModal/ApprovalModal.tsx @@ -7,6 +7,7 @@ export interface ApprovalModalProps { isVisible: boolean; onCancel: () => void; children: React.ReactNode; + avoidKeyboard?: boolean; } const styles = StyleSheet.create({ @@ -33,6 +34,7 @@ const ApprovalModal = (props: ApprovalModalProps) => { onSwipeComplete={props.onCancel} swipeDirection={'down'} propagateSwipe + avoidKeyboard={props.avoidKeyboard} > {props.children} diff --git a/app/components/Approvals/ApprovalModal/__snapshots__/ApprovalModal.test.tsx.snap b/app/components/Approvals/ApprovalModal/__snapshots__/ApprovalModal.test.tsx.snap index 323137ebfa6..fdbad0398c8 100644 --- a/app/components/Approvals/ApprovalModal/__snapshots__/ApprovalModal.test.tsx.snap +++ b/app/components/Approvals/ApprovalModal/__snapshots__/ApprovalModal.test.tsx.snap @@ -52,7 +52,7 @@ exports[`ApprovalModal renders 1`] = ` onStartShouldSetResponder={[Function]} style={ { - "backgroundColor": "#00000099", + "backgroundColor": "#00000066", "bottom": 0, "height": 1334, "left": 0, diff --git a/app/components/Approvals/FlowLoaderModal/FlowLoaderModal.tsx b/app/components/Approvals/FlowLoaderModal/FlowLoaderModal.tsx index 302f5ea2725..7146ef70e4b 100644 --- a/app/components/Approvals/FlowLoaderModal/FlowLoaderModal.tsx +++ b/app/components/Approvals/FlowLoaderModal/FlowLoaderModal.tsx @@ -2,7 +2,7 @@ import React, { useCallback } from 'react'; import useApprovalRequest from '../../Views/confirmations/hooks/useApprovalRequest'; import ApprovalModal from '../ApprovalModal'; import useApprovalFlow from '../../Views/confirmations/hooks/useApprovalFlow'; -import ApprovalFlowLoader from '../../Views/confirmations/components/Approval/ApprovalFlowLoader'; +import ApprovalFlowLoader from '../../Views/confirmations/legacy/components/Approval/ApprovalFlowLoader'; const FlowLoaderModal = () => { const { approvalRequest } = useApprovalRequest(); diff --git a/app/components/Approvals/InstallSnapApproval/InstallSnapApproval.tsx b/app/components/Approvals/InstallSnapApproval/InstallSnapApproval.tsx index 1e075401dc1..e866275d833 100644 --- a/app/components/Approvals/InstallSnapApproval/InstallSnapApproval.tsx +++ b/app/components/Approvals/InstallSnapApproval/InstallSnapApproval.tsx @@ -1,7 +1,9 @@ ///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps,external-snaps) import React, { useEffect, useState } from 'react'; import ApprovalModal from '../ApprovalModal'; -import useApprovalRequest, { ApprovalRequestType } from '../../Views/confirmations/hooks/useApprovalRequest'; +import useApprovalRequest, { + ApprovalRequestType, +} from '../../Views/confirmations/hooks/useApprovalRequest'; import { ApprovalTypes } from '../../../core/RPCMethods/RPCMethodMiddleware'; import { SnapInstallState } from './InstallSnapApproval.types'; import { @@ -165,7 +167,11 @@ const InstallSnapApproval = () => { const content = renderModalContent(); return content ? ( - + {content} ) : null; diff --git a/app/components/Approvals/SignatureApproval/SignatureApproval.tsx b/app/components/Approvals/SignatureApproval/SignatureApproval.tsx index 11c3d315541..737b8689a7f 100644 --- a/app/components/Approvals/SignatureApproval/SignatureApproval.tsx +++ b/app/components/Approvals/SignatureApproval/SignatureApproval.tsx @@ -1,7 +1,7 @@ import React, { useCallback, useEffect } from 'react'; import useApprovalRequest from '../../Views/confirmations/hooks/useApprovalRequest'; import { ApprovalTypes } from '../../../core/RPCMethods/RPCMethodMiddleware'; -import SignatureRequestRoot from '../../Views/confirmations/components/SignatureRequest/Root'; +import SignatureRequestRoot from '../../Views/confirmations/legacy/components/SignatureRequest/Root'; import { endTrace, TraceName } from '../../../util/trace'; const SignatureApproval = () => { diff --git a/app/components/Approvals/SnapAccountCustomNameApproval/SnapAccountCustomNameApproval.styles.ts b/app/components/Approvals/SnapAccountCustomNameApproval/SnapAccountCustomNameApproval.styles.ts index ce8c32319f5..5e8f8cecdef 100644 --- a/app/components/Approvals/SnapAccountCustomNameApproval/SnapAccountCustomNameApproval.styles.ts +++ b/app/components/Approvals/SnapAccountCustomNameApproval/SnapAccountCustomNameApproval.styles.ts @@ -37,6 +37,7 @@ const styleSheet = (params: { theme: Theme }) => { borderRadius: 4, padding: 10, marginVertical: 10, + color: colors.text.default, }, }); }; diff --git a/app/components/Approvals/SnapAccountCustomNameApproval/SnapAccountCustomNameApproval.tsx b/app/components/Approvals/SnapAccountCustomNameApproval/SnapAccountCustomNameApproval.tsx index 7853f97fbaf..f2f21de003d 100644 --- a/app/components/Approvals/SnapAccountCustomNameApproval/SnapAccountCustomNameApproval.tsx +++ b/app/components/Approvals/SnapAccountCustomNameApproval/SnapAccountCustomNameApproval.tsx @@ -88,6 +88,7 @@ const SnapAccountCustomNameApproval = () => { approvalRequest?.type === SNAP_MANAGE_ACCOUNTS_CONFIRMATION_TYPES.showNameSnapAccount } + avoidKeyboard onCancel={onReject} > diff --git a/app/components/Approvals/TemplateConfirmationModal/TemplateConfirmationModal.tsx b/app/components/Approvals/TemplateConfirmationModal/TemplateConfirmationModal.tsx index f527fb52b41..a1ed95e5fcf 100644 --- a/app/components/Approvals/TemplateConfirmationModal/TemplateConfirmationModal.tsx +++ b/app/components/Approvals/TemplateConfirmationModal/TemplateConfirmationModal.tsx @@ -2,8 +2,8 @@ import React from 'react'; import useApprovalRequest from '../../Views/confirmations/hooks/useApprovalRequest'; import { ApprovalTypes } from '../../../core/RPCMethods/RPCMethodMiddleware'; import ApprovalModal from '../ApprovalModal'; -import TemplateConfirmation from '../../Views/confirmations/components/Approval/TemplateConfirmation/TemplateConfirmation'; -import { TEMPLATED_CONFIRMATION_APPROVAL_TYPES } from '../../Views/confirmations/components/Approval/TemplateConfirmation/Templates'; +import TemplateConfirmation from '../../Views/confirmations/legacy/components/Approval/TemplateConfirmation/TemplateConfirmation'; +import { TEMPLATED_CONFIRMATION_APPROVAL_TYPES } from '../../Views/confirmations/legacy/components/Approval/TemplateConfirmation/Templates'; const TemplateConfirmationModal = () => { const { approvalRequest, onConfirm, onReject } = useApprovalRequest(); diff --git a/app/components/Approvals/TransactionApproval/TransactionApproval.tsx b/app/components/Approvals/TransactionApproval/TransactionApproval.tsx index 96055d0e77d..5abcb45776b 100644 --- a/app/components/Approvals/TransactionApproval/TransactionApproval.tsx +++ b/app/components/Approvals/TransactionApproval/TransactionApproval.tsx @@ -1,8 +1,8 @@ import React, { useCallback, useState } from 'react'; import useApprovalRequest from '../../Views/confirmations/hooks/useApprovalRequest'; import { ApprovalTypes } from '../../../core/RPCMethods/RPCMethodMiddleware'; -import Approval from '../../Views/confirmations/Approval'; -import Approve from '../../Views/confirmations/ApproveView/Approve'; +import Approval from '../../Views/confirmations/legacy/Approval'; +import Approve from '../../Views/confirmations/legacy/ApproveView/Approve'; import QRSigningModal from '../../UI/QRHardware/QRSigningModal'; import withQRHardwareAwareness from '../../UI/QRHardware/withQRHardwareAwareness'; import { IQRState } from '../../UI/QRHardware/types'; diff --git a/app/components/Approvals/WatchAssetApproval/WatchAssetApproval.tsx b/app/components/Approvals/WatchAssetApproval/WatchAssetApproval.tsx index a402c54987f..075add99396 100644 --- a/app/components/Approvals/WatchAssetApproval/WatchAssetApproval.tsx +++ b/app/components/Approvals/WatchAssetApproval/WatchAssetApproval.tsx @@ -1,6 +1,6 @@ import React from 'react'; import useApprovalRequest from '../../Views/confirmations/hooks/useApprovalRequest'; -import WatchAssetRequest from '../../Views/confirmations/components/WatchAssetRequest'; +import WatchAssetRequest from '../../Views/confirmations/legacy/components/WatchAssetRequest'; import { ApprovalTypes } from '../../../core/RPCMethods/RPCMethodMiddleware'; import ApprovalModal from '../ApprovalModal'; diff --git a/app/components/Base/RemoteImage/__snapshots__/index.test.tsx.snap b/app/components/Base/RemoteImage/__snapshots__/index.test.tsx.snap index 5f208674613..276b4652b56 100644 --- a/app/components/Base/RemoteImage/__snapshots__/index.test.tsx.snap +++ b/app/components/Base/RemoteImage/__snapshots__/index.test.tsx.snap @@ -104,14 +104,14 @@ exports[`RemoteImage should render with Solana network badge when on Solana netw style={ { "alignItems": "center", - "backgroundColor": "#f2f4f6", + "backgroundColor": "#f3f5f9", "borderColor": "#ffffff", "borderRadius": 8, "borderWidth": 1, "height": 16, "justifyContent": "center", "overflow": "hidden", - "shadowColor": "#0000001A", + "shadowColor": "#0000001a", "shadowOffset": { "height": 2, "width": 0, @@ -126,8 +126,8 @@ exports[`RemoteImage should render with Solana network badge when on Solana netw accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", + "color": "#121314", + "fontFamily": "CentraNo1-Book", "fontSize": 10, "fontWeight": "400", "letterSpacing": 0, diff --git a/app/components/Base/RemoteImage/index.js b/app/components/Base/RemoteImage/index.js index f7a574b02ee..fd7bfa1950a 100644 --- a/app/components/Base/RemoteImage/index.js +++ b/app/components/Base/RemoteImage/index.js @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import { Image, @@ -21,13 +21,10 @@ import Badge, { BadgeVariant, } from '../../../component-library/components/Badges/Badge'; import { useSelector } from 'react-redux'; -import { - selectChainId, - selectEvmTicker, -} from '../../../selectors/networkController'; +import { selectChainId } from '../../../selectors/networkController'; import { getTestNetImageByChainId, - isLineaMainnet, + isLineaMainnetChainId, isMainNet, isSolanaMainnet, isTestNet, @@ -39,6 +36,12 @@ import { BadgeAnchorElementShape } from '../../../component-library/components/B import useSvgUriViewBox from '../../hooks/useSvgUriViewBox'; import { AvatarSize } from '../../../component-library/components/Avatars/Avatar'; import Logger from '../../../util/Logger'; +import { toHex } from '@metamask/controller-utils'; +import { + CustomNetworkImgMapping, + PopularList, + UnpopularNetworkList, +} from '../../../util/networks/customNetworks'; const createStyles = () => StyleSheet.create({ @@ -65,8 +68,10 @@ const RemoteImage = (props) => { const isImageUrl = isUrl(props?.source?.uri); const ipfsGateway = useIpfsGateway(); const styles = createStyles(); - const chainId = useSelector(selectChainId); - const ticker = useSelector(selectEvmTicker); + const currentChainId = useSelector(selectChainId); + // The chainId would be passed in props from parent for collectible media + //TODO remove once migrated to TS and chainID is properly typed to hex + const chainId = props.chainId ? toHex(props.chainId) : currentChainId; const networkName = useSelector(selectNetworkName); const [resolvedIpfsUrl, setResolvedIpfsUrl] = useState(false); @@ -132,17 +137,33 @@ const RemoteImage = (props) => { ); }, [uri]); - const NetworkBadgeSource = () => { + const NetworkBadgeSource = useCallback(() => { if (isTestNet(chainId)) return getTestNetImageByChainId(chainId); if (isMainNet(chainId)) return images.ETHEREUM; - if (isLineaMainnet(chainId)) return images['LINEA-MAINNET']; + if (isLineaMainnetChainId(chainId)) return images['LINEA-MAINNET']; if (isSolanaMainnet(chainId)) return images.SOLANA; - return ticker ? images[ticker] : undefined; - }; + const unpopularNetwork = UnpopularNetworkList.find( + (networkConfig) => networkConfig.chainId === chainId, + ); + + const popularNetwork = PopularList.find( + (networkConfig) => networkConfig.chainId === chainId, + ); + const network = unpopularNetwork || popularNetwork; + const customNetworkImg = CustomNetworkImgMapping[chainId]; + + if (network) { + return network.rpcPrefs.imageSource; + } else if (customNetworkImg) { + return customNetworkImg; + } + return undefined; + }, [chainId]); + const isSVG = source && source.uri && @@ -290,6 +311,7 @@ RemoteImage.propTypes = { isTokenImage: PropTypes.bool, isFullRatio: PropTypes.bool, + chainId: PropTypes.string, }; export default RemoteImage; diff --git a/app/components/Nav/App/App.tsx b/app/components/Nav/App/App.tsx index 5d023da1f8d..b7220be14ee 100644 --- a/app/components/Nav/App/App.tsx +++ b/app/components/Nav/App/App.tsx @@ -5,11 +5,7 @@ import React, { useRef, useState, } from 'react'; -import { - CommonActions, - useNavigation, - useRoute, -} from '@react-navigation/native'; +import { useNavigation, useRoute } from '@react-navigation/native'; import { Linking } from 'react-native'; import { createStackNavigator } from '@react-navigation/stack'; import Login from '../../Views/Login'; @@ -136,6 +132,7 @@ import { selectUserLoggedIn } from '../../../reducers/user/selectors'; import { Confirm } from '../../Views/confirmations/Confirm'; ///: BEGIN:ONLY_INCLUDE_IF(multi-srp) import ImportNewSecretRecoveryPhrase from '../../Views/ImportNewSecretRecoveryPhrase'; +import { SelectSRPBottomSheet } from '../../Views/SelectSRP/SelectSRPBottomSheet'; ///: END:ONLY_INCLUDE_IF import NavigationService from '../../../core/NavigationService'; @@ -306,7 +303,18 @@ const DetectedTokensFlow = () => ( ); -const RootModalFlow = () => ( +///: BEGIN:ONLY_INCLUDE_IF(multi-srp) +interface RootModalFlowProps { + route: { + params: Record; + }; +} +///: END:ONLY_INCLUDE_IF(multi-srp) +const RootModalFlow = ( + ///: BEGIN:ONLY_INCLUDE_IF(multi-srp) + props: RootModalFlowProps, + ///: END:ONLY_INCLUDE_IF +) => ( ( name={Routes.MODAL.ENABLE_AUTOMATIC_SECURITY_CHECKS} component={EnableAutomaticSecurityChecksModal} /> - + { + ///: BEGIN:ONLY_INCLUDE_IF(multi-srp) + + ///: END:ONLY_INCLUDE_IF + } + ( headerShown: false, }} > - + ); ///: END:ONLY_INCLUDE_IF @@ -727,15 +752,10 @@ const App: React.FC = () => { } catch (error) { const errorMessage = (error as Error).message; // if there are no credentials, then they were cleared in the last session and we should not show biometrics on the login screen - if (errorMessage === AUTHENTICATION_APP_TRIGGERED_AUTH_NO_CREDENTIALS) { - navigation.dispatch( - CommonActions.setParams({ - locked: true, - }), - ); - } + const locked = + errorMessage === AUTHENTICATION_APP_TRIGGERED_AUTH_NO_CREDENTIALS; - await Authentication.lockApp({ reset: false }); + await Authentication.lockApp({ reset: false, locked }); trackErrorAsAnalytics( 'App: Max Attempts Reached', errorMessage, diff --git a/app/components/Nav/Main/MainNavigator.js b/app/components/Nav/Main/MainNavigator.js index b25c61c8ccf..018c5ef58fa 100644 --- a/app/components/Nav/Main/MainNavigator.js +++ b/app/components/Nav/Main/MainNavigator.js @@ -25,8 +25,8 @@ import Asset from '../../Views/Asset'; import AssetDetails from '../../Views/AssetDetails'; import AddAsset from '../../Views/AddAsset'; import Collectible from '../../Views/Collectible'; -import Send from '../../Views/confirmations/Send'; -import SendTo from '../../Views/confirmations/SendFlow/SendTo'; +import Send from '../../Views/confirmations/legacy/Send'; +import SendTo from '../../Views/confirmations/legacy/SendFlow/SendTo'; import { RevealPrivateCredential } from '../../Views/RevealPrivateCredential'; import WalletConnectSessions from '../../Views/WalletConnectSessions'; import OfflineMode from '../../Views/OfflineMode'; @@ -41,8 +41,8 @@ import ManualBackupStep2 from '../../Views/ManualBackupStep2'; import ManualBackupStep3 from '../../Views/ManualBackupStep3'; import PaymentRequest from '../../UI/PaymentRequest'; import PaymentRequestSuccess from '../../UI/PaymentRequestSuccess'; -import Amount from '../../Views/confirmations/SendFlow/Amount'; -import Confirm from '../../Views/confirmations/SendFlow/Confirm'; +import Amount from '../../Views/confirmations/legacy/SendFlow/Amount'; +import Confirm from '../../Views/confirmations/legacy/SendFlow/Confirm'; import ContactForm from '../../Views/Settings/Contacts/ContactForm'; import ActivityView from '../../Views/ActivityView'; import SwapsAmountView from '../../UI/Swaps'; @@ -195,7 +195,11 @@ const WalletTabModalFlow = () => ( const TransactionsHome = () => ( - + { useEffect(() => { stopIncomingTransactionPolling(); - - if (showIncomingTransactionsNetworks[chainId]) { - startIncomingTransactionPolling([chainId]); - } - }, [chainId, networkClientId, showIncomingTransactionsNetworks]); + startIncomingTransactionPolling(); + }, [ + chainId, + networkClientId, + showIncomingTransactionsNetworks, + props.networkConfigurations, + ]); const checkInfuraAvailability = useCallback(async () => { if (props.providerType !== 'rpc') { @@ -185,11 +187,11 @@ const Main = (props) => { removeNotVisibleNotifications(); BackgroundTimer.runBackgroundTimer(async () => { - await updateIncomingTransactions([props.chainId]); + await updateIncomingTransactions(); }, AppConstants.TX_CHECK_BACKGROUND_FREQUENCY); } }, - [backgroundMode, removeNotVisibleNotifications, props.chainId], + [backgroundMode, removeNotVisibleNotifications], ); const initForceReload = () => { @@ -511,6 +513,10 @@ Main.propTypes = { * ID of the global network client */ networkClientId: PropTypes.string, + /** + * Network configurations + */ + networkConfigurations: PropTypes.object, }; const mapStateToProps = (state) => ({ @@ -520,6 +526,7 @@ const mapStateToProps = (state) => ({ chainId: selectChainId(state), networkClientId: selectNetworkClientId(state), backUpSeedphraseVisible: state.user.backUpSeedphraseVisible, + networkConfigurations: selectNetworkConfigurations(state), }); const mapDispatchToProps = (dispatch) => ({ diff --git a/app/components/Snaps/SnapDialogApproval/SnapDialogApproval.styles.ts b/app/components/Snaps/SnapDialogApproval/SnapDialogApproval.styles.ts index 0ed681b4019..cfa7e88241a 100644 --- a/app/components/Snaps/SnapDialogApproval/SnapDialogApproval.styles.ts +++ b/app/components/Snaps/SnapDialogApproval/SnapDialogApproval.styles.ts @@ -19,11 +19,14 @@ const styleSheet = (params: { theme: Theme }) => { borderTopRightRadius: 24, minHeight: 200, paddingBottom: Device.isIphoneX() ? 20 : 0, + maxHeight: '80%', }, - actionContainer: { - flex: 0, + footer: { + position: 'absolute', + bottom: 20, + width: '100%', paddingVertical: 16, - justifyContent: 'center', + height: 80, }, }); }; diff --git a/app/components/Snaps/SnapDialogApproval/SnapDialogApproval.tsx b/app/components/Snaps/SnapDialogApproval/SnapDialogApproval.tsx index 922bee393f0..19a3b89746b 100644 --- a/app/components/Snaps/SnapDialogApproval/SnapDialogApproval.tsx +++ b/app/components/Snaps/SnapDialogApproval/SnapDialogApproval.tsx @@ -116,6 +116,7 @@ const SnapDialogApproval = () => { approvalRequest?.type === DIALOG_APPROVAL_TYPES.default } onCancel={onCancel} + avoidKeyboard > { isLoading={isLoading} onCancel={onCancel} useFooter={approvalRequest?.type === DIALOG_APPROVAL_TYPES.default} + // eslint-disable-next-line react-native/no-inline-styles + style={{ + marginBottom: + approvalRequest?.type !== DIALOG_APPROVAL_TYPES.default ? 80 : 0, + }} /> {approvalRequest?.type !== DIALOG_APPROVAL_TYPES.default && ( - - - + )} diff --git a/app/components/Snaps/SnapUIAddress/SnapUIAddress.tsx b/app/components/Snaps/SnapUIAddress/SnapUIAddress.tsx index e1abb7e7518..eaf5d460d2f 100644 --- a/app/components/Snaps/SnapUIAddress/SnapUIAddress.tsx +++ b/app/components/Snaps/SnapUIAddress/SnapUIAddress.tsx @@ -22,6 +22,7 @@ export interface SnapUIAddressProps { truncate?: boolean; displayName?: boolean; avatar?: boolean; + color?: string; } export const SnapUIAddress: React.FunctionComponent = ({ @@ -30,6 +31,7 @@ export const SnapUIAddress: React.FunctionComponent = ({ truncate = true, displayName = false, avatar = true, + color, }) => { const caipIdentifier = useMemo(() => { if (isHexString(address)) { @@ -58,6 +60,7 @@ export const SnapUIAddress: React.FunctionComponent = ({ const name = useDisplayName(parsed); + // TODO: This component should inherit font color, e.g. for link. return ( = ({ gap={8} > {avatar && } - + {displayName && name ? name : formattedAddress} diff --git a/app/components/Snaps/SnapUIAddress/__snapshots__/SnapUIAddress.test.tsx.snap b/app/components/Snaps/SnapUIAddress/__snapshots__/SnapUIAddress.test.tsx.snap index 1df64d384a8..1ac308186fb 100644 --- a/app/components/Snaps/SnapUIAddress/__snapshots__/SnapUIAddress.test.tsx.snap +++ b/app/components/Snaps/SnapUIAddress/__snapshots__/SnapUIAddress.test.tsx.snap @@ -148,12 +148,12 @@ exports[`SnapUIAddress renders Bitcoin address 1`] = ` accessibilityRole="text" style={ { - "color": "inherit", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -192,12 +192,12 @@ exports[`SnapUIAddress renders Bitcoin address with blockie 1`] = ` accessibilityRole="text" style={ { - "color": "inherit", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -354,12 +354,12 @@ exports[`SnapUIAddress renders Cosmos address 1`] = ` accessibilityRole="text" style={ { - "color": "inherit", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -398,12 +398,12 @@ exports[`SnapUIAddress renders Cosmos address with blockie 1`] = ` accessibilityRole="text" style={ { - "color": "inherit", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -560,12 +560,12 @@ exports[`SnapUIAddress renders Ethereum address 1`] = ` accessibilityRole="text" style={ { - "color": "inherit", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -604,12 +604,12 @@ exports[`SnapUIAddress renders Ethereum address with blockie 1`] = ` accessibilityRole="text" style={ { - "color": "inherit", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -766,12 +766,12 @@ exports[`SnapUIAddress renders Hedera address 1`] = ` accessibilityRole="text" style={ { - "color": "inherit", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -810,12 +810,12 @@ exports[`SnapUIAddress renders Hedera address with blockie 1`] = ` accessibilityRole="text" style={ { - "color": "inherit", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -972,12 +972,12 @@ exports[`SnapUIAddress renders Polkadot address 1`] = ` accessibilityRole="text" style={ { - "color": "inherit", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -1016,12 +1016,12 @@ exports[`SnapUIAddress renders Polkadot address with blockie 1`] = ` accessibilityRole="text" style={ { - "color": "inherit", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -1178,12 +1178,12 @@ exports[`SnapUIAddress renders Starknet address 1`] = ` accessibilityRole="text" style={ { - "color": "inherit", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -1222,12 +1222,12 @@ exports[`SnapUIAddress renders Starknet address with blockie 1`] = ` accessibilityRole="text" style={ { - "color": "inherit", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -1384,12 +1384,12 @@ exports[`SnapUIAddress renders legacy Ethereum address 1`] = ` accessibilityRole="text" style={ { - "color": "inherit", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > diff --git a/app/components/Snaps/SnapUIButton/SnapUIButton.tsx b/app/components/Snaps/SnapUIButton/SnapUIButton.tsx index e4729cbe623..c7fecac5bb2 100644 --- a/app/components/Snaps/SnapUIButton/SnapUIButton.tsx +++ b/app/components/Snaps/SnapUIButton/SnapUIButton.tsx @@ -1,41 +1,24 @@ import React, { FunctionComponent } from 'react'; import { ButtonType, UserInputEventType } from '@metamask/snaps-sdk'; -import ButtonLink from '../../../component-library/components/Buttons/Button/variants/ButtonLink'; -import { ButtonLinkProps } from '../../../component-library/components/Buttons/Button/variants/ButtonLink/ButtonLink.types'; +import { TouchableOpacity } from 'react-native'; import { useSnapInterfaceContext } from '../SnapInterfaceContext'; -import Text, { - TextColor, - TextVariant, -} from '../../../component-library/components/Texts/Text'; import AnimatedLottieView from 'lottie-react-native'; export interface SnapUIButtonProps { name?: string; + disabled?: boolean; loading?: boolean; type?: ButtonType; form?: string; - variant: keyof typeof COLORS; - textVariant?: TextVariant; } -const COLORS = { - primary: TextColor.Info, - destructive: TextColor.Error, - disabled: TextColor.Muted, -}; - -export const SnapUIButton: FunctionComponent< - SnapUIButtonProps & ButtonLinkProps -> = ({ +export const SnapUIButton: FunctionComponent = ({ name, children, form, type = ButtonType.Button, - variant = 'primary', disabled = false, loading = false, - textVariant, - ...props }) => { const { handleEvent } = useSnapInterfaceContext(); @@ -54,34 +37,22 @@ export const SnapUIButton: FunctionComponent< } }; - const overriddenVariant = disabled ? 'disabled' : variant; - - const color = COLORS[overriddenVariant as keyof typeof COLORS]; - return ( - - ) : ( - - {children} - - ) - } - /> + + {loading ? ( + + ) : ( + children + )} + ); }; diff --git a/app/components/Snaps/SnapUIFooterButton/SnapUIFooterButton.tsx b/app/components/Snaps/SnapUIFooterButton/SnapUIFooterButton.tsx index eee244c1269..e3aeffa6a41 100644 --- a/app/components/Snaps/SnapUIFooterButton/SnapUIFooterButton.tsx +++ b/app/components/Snaps/SnapUIFooterButton/SnapUIFooterButton.tsx @@ -11,10 +11,7 @@ import { SnapIcon } from '../SnapIcon/SnapIcon'; import Text from '../../../component-library/components/Texts/Text'; import { useSelector } from 'react-redux'; import { selectSnaps } from '../../../selectors/snaps/snapController'; -import { - DEFAULT_BUTTONPRIMARY_LABEL_COLOR, - DEFAULT_BUTTONPRIMARY_LABEL_TEXTVARIANT, -} from '../../../component-library/components/Buttons/Button/variants/ButtonPrimary/ButtonPrimary.constants'; +import { DEFAULT_BUTTONPRIMARY_LABEL_TEXTVARIANT } from '../../../component-library/components/Buttons/Button/variants/ButtonPrimary/ButtonPrimary.constants'; import { FlexDirection, JustifyContent, @@ -32,7 +29,7 @@ const localStyles = StyleSheet.create({ flexDirection: FlexDirection.Row, alignItems: AlignItems.center, justifyContent: JustifyContent.center, - gap: 4, + gap: 8, }, }); @@ -98,10 +95,7 @@ export const SnapUIFooterButton: FunctionComponent = ({ const buttonLabel = () => { if (loading) { return ( - + ); } else if (isSnapAction && !hideSnapBranding) { return ( @@ -109,7 +103,7 @@ export const SnapUIFooterButton: FunctionComponent = ({ {children} @@ -121,7 +115,7 @@ export const SnapUIFooterButton: FunctionComponent = ({ variant={DEFAULT_BUTTONPRIMARY_LABEL_TEXTVARIANT} color={ variant === ButtonVariants.Primary - ? DEFAULT_BUTTONPRIMARY_LABEL_COLOR + ? theme.colors.primary.inverse : theme.colors.primary.default } > diff --git a/app/components/Snaps/SnapUIInput/SnapUIInput.tsx b/app/components/Snaps/SnapUIInput/SnapUIInput.tsx index 7677e44af5c..4e286fe094f 100644 --- a/app/components/Snaps/SnapUIInput/SnapUIInput.tsx +++ b/app/components/Snaps/SnapUIInput/SnapUIInput.tsx @@ -72,6 +72,8 @@ export const SnapUIInput = ({ id={name} value={value} onChangeText={handleChange} + autoCapitalize="none" + autoCorrect={false} /> {error && ( // eslint-disable-next-line react-native/no-inline-styles diff --git a/app/components/Snaps/SnapUIRenderer/SnapUIRenderer.test.tsx b/app/components/Snaps/SnapUIRenderer/SnapUIRenderer.test.tsx index 8449c8e2243..0dde3e17979 100644 --- a/app/components/Snaps/SnapUIRenderer/SnapUIRenderer.test.tsx +++ b/app/components/Snaps/SnapUIRenderer/SnapUIRenderer.test.tsx @@ -297,13 +297,20 @@ describe('SnapUIRenderer', () => { it('re-renders when the interface changes', () => { const { toJSON, getAllByTestId, updateInterface, getRenderCount } = - renderInterface(Box({ children: Input({ name: 'input' }) })); + renderInterface( + Box({ children: Input({ name: 'input', type: 'number' }) }), + ); const inputs = getAllByTestId('input'); expect(inputs).toHaveLength(1); updateInterface( - Box({ children: [Input({ name: 'input' }), Input({ name: 'input2' })] }), + Box({ + children: [ + Input({ name: 'input', type: 'number' }), + Input({ name: 'input2', type: 'password' }), + ], + }), ); const inputsAfterRerender = getAllByTestId('input'); diff --git a/app/components/Snaps/SnapUIRenderer/SnapUIRenderer.tsx b/app/components/Snaps/SnapUIRenderer/SnapUIRenderer.tsx index 7dcf925fbbc..03a495b650f 100644 --- a/app/components/Snaps/SnapUIRenderer/SnapUIRenderer.tsx +++ b/app/components/Snaps/SnapUIRenderer/SnapUIRenderer.tsx @@ -1,12 +1,11 @@ import React, { memo, useMemo, useRef } from 'react'; import { useSelector } from 'react-redux'; -import { Box } from '../../UI/Box/Box'; import { isEqual } from 'lodash'; import { getMemoizedInterface } from '../../../selectors/snaps/interfaceController'; import { SnapInterfaceContextProvider } from '../SnapInterfaceContext'; import { mapToTemplate } from './utils'; import TemplateRenderer from '../../UI/TemplateRenderer'; -import { ActivityIndicator, View } from 'react-native'; +import { ActivityIndicator, View, ViewStyle } from 'react-native'; import { Colors } from 'react-native/Libraries/NewAppScreen'; import { Container } from '@metamask/snaps-sdk/jsx'; import { strings } from '../../../../locales/i18n'; @@ -21,6 +20,7 @@ interface SnapUIRendererProps { interfaceId: string; onCancel?: () => void; useFooter: boolean; + style?: ViewStyle; PERF_DEBUG?: boolean; // DO NOT USE IN PRODUCTION } @@ -39,6 +39,7 @@ const SnapUIRendererComponent = ({ interfaceId, onCancel, useFooter, + style, PERF_DEBUG, }: SnapUIRendererProps) => { const theme = useTheme(); @@ -75,7 +76,7 @@ const SnapUIRendererComponent = ({ const { state: initialState, context } = interfaceState; return ( - + {PERF_DEBUG && } - + ); }; diff --git a/app/components/Snaps/SnapUIRenderer/__snapshots__/SnapUIRenderer.test.tsx.snap b/app/components/Snaps/SnapUIRenderer/__snapshots__/SnapUIRenderer.test.tsx.snap index 86f3eda791a..4ec4139043e 100644 --- a/app/components/Snaps/SnapUIRenderer/__snapshots__/SnapUIRenderer.test.tsx.snap +++ b/app/components/Snaps/SnapUIRenderer/__snapshots__/SnapUIRenderer.test.tsx.snap @@ -4,11 +4,11 @@ exports[`SnapUIRenderer adds a footer if required 1`] = ` @@ -53,21 +53,31 @@ exports[`SnapUIRenderer adds a footer if required 1`] = ` > Hello world! @@ -110,7 +120,7 @@ exports[`SnapUIRenderer adds a footer if required 1`] = ` "alignItems": "center", "alignSelf": "flex-start", "backgroundColor": "transparent", - "borderColor": "#0376c9", + "borderColor": "#4459ff", "borderRadius": 24, "borderWidth": 1, "flex": 1, @@ -125,12 +135,12 @@ exports[`SnapUIRenderer adds a footer if required 1`] = ` accessibilityRole="text" style={ { - "color": "#ffffff", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#4459ff", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -150,11 +160,11 @@ exports[`SnapUIRenderer prefills interactive inputs with existing state 1`] = ` @@ -210,7 +220,7 @@ exports[`SnapUIRenderer prefills interactive inputs with existing state 1`] = ` { "alignItems": "center", "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 8, "borderWidth": 1, "flexDirection": "row", @@ -229,6 +239,8 @@ exports[`SnapUIRenderer prefills interactive inputs with existing state 1`] = ` } > @@ -331,7 +343,7 @@ exports[`SnapUIRenderer re-renders when the interface changes 1`] = ` { "alignItems": "center", "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 8, "borderWidth": 1, "flexDirection": "row", @@ -350,9 +362,12 @@ exports[`SnapUIRenderer re-renders when the interface changes 1`] = ` } > @@ -511,7 +529,7 @@ exports[`SnapUIRenderer re-syncs state when the interface changes 1`] = ` { "alignItems": "center", "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 8, "borderWidth": 1, "flexDirection": "row", @@ -530,6 +548,8 @@ exports[`SnapUIRenderer re-syncs state when the interface changes 1`] = ` } > @@ -680,21 +702,31 @@ exports[`SnapUIRenderer renders basic UI 1`] = ` > Hello world! @@ -714,11 +746,11 @@ exports[`SnapUIRenderer renders complex nested components 1`] = ` @@ -762,7 +794,7 @@ exports[`SnapUIRenderer renders complex nested components 1`] = ` } > @@ -846,12 +878,12 @@ exports[`SnapUIRenderer renders complex nested components 1`] = ` accessibilityRole="text" style={ { - "color": "#9fa6ae", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#9ca1af", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -861,12 +893,12 @@ exports[`SnapUIRenderer renders complex nested components 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -962,12 +994,12 @@ exports[`SnapUIRenderer renders complex nested components 1`] = ` ellipsizeMode="tail" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -978,12 +1010,12 @@ exports[`SnapUIRenderer renders complex nested components 1`] = ` ellipsizeMode="tail" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -1009,12 +1041,12 @@ exports[`SnapUIRenderer renders complex nested components 1`] = ` ellipsizeMode="tail" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -1025,12 +1057,12 @@ exports[`SnapUIRenderer renders complex nested components 1`] = ` ellipsizeMode="tail" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -1076,7 +1108,7 @@ exports[`SnapUIRenderer renders complex nested components 1`] = ` "alignItems": "center", "alignSelf": "flex-start", "backgroundColor": "transparent", - "borderColor": "#0376c9", + "borderColor": "#4459ff", "borderRadius": 24, "borderWidth": 1, "flex": 1, @@ -1091,12 +1123,12 @@ exports[`SnapUIRenderer renders complex nested components 1`] = ` accessibilityRole="text" style={ { - "color": "#0376c9", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#4459ff", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -1115,7 +1147,7 @@ exports[`SnapUIRenderer renders complex nested components 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#141618", + "backgroundColor": "#121314", "borderRadius": 24, "flex": 1, "flexDirection": "row", @@ -1124,14 +1156,13 @@ exports[`SnapUIRenderer renders complex nested components 1`] = ` "paddingHorizontal": 16, } } - textVariant="sBodyMDMedium" > @@ -1171,16 +1202,27 @@ exports[`SnapUIRenderer renders complex nested components 1`] = ` style={ { "color": "#ffffff", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > Foo @@ -1200,11 +1242,11 @@ exports[`SnapUIRenderer renders footers 1`] = ` @@ -1249,21 +1291,31 @@ exports[`SnapUIRenderer renders footers 1`] = ` > Hello world! @@ -1305,7 +1357,7 @@ exports[`SnapUIRenderer renders footers 1`] = ` "alignItems": "center", "alignSelf": "flex-start", "backgroundColor": "transparent", - "borderColor": "#0376c9", + "borderColor": "#4459ff", "borderRadius": 24, "borderWidth": 1, "flex": 1, @@ -1320,12 +1372,12 @@ exports[`SnapUIRenderer renders footers 1`] = ` accessibilityRole="text" style={ { - "color": "#0376c9", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#4459ff", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -1344,7 +1396,7 @@ exports[`SnapUIRenderer renders footers 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#141618", + "backgroundColor": "#121314", "borderRadius": 24, "flex": 1, "flexDirection": "row", @@ -1353,14 +1405,13 @@ exports[`SnapUIRenderer renders footers 1`] = ` "paddingHorizontal": 16, } } - textVariant="sBodyMDMedium" > @@ -1400,16 +1451,27 @@ exports[`SnapUIRenderer renders footers 1`] = ` style={ { "color": "#ffffff", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > Foo @@ -1436,11 +1498,11 @@ exports[`SnapUIRenderer supports fields with multiple components 1`] = ` @@ -1512,12 +1574,12 @@ exports[`SnapUIRenderer supports fields with multiple components 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } testID="label" @@ -1529,7 +1591,7 @@ exports[`SnapUIRenderer supports fields with multiple components 1`] = ` { "alignItems": "center", "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 8, "borderWidth": 1, "flexDirection": "row", @@ -1594,6 +1656,8 @@ exports[`SnapUIRenderer supports fields with multiple components 1`] = ` } > - - - Submit - + Submit - + @@ -1688,11 +1732,11 @@ exports[`SnapUIRenderer supports forms with fields 1`] = ` @@ -1764,12 +1808,12 @@ exports[`SnapUIRenderer supports forms with fields 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } testID="label" @@ -1781,7 +1825,7 @@ exports[`SnapUIRenderer supports forms with fields 1`] = ` { "alignItems": "center", "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 8, "borderWidth": 1, "flexDirection": "row", @@ -1800,6 +1844,8 @@ exports[`SnapUIRenderer supports forms with fields 1`] = ` } > @@ -1944,12 +1990,12 @@ exports[`SnapUIRenderer supports forms with fields 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } testID="label" @@ -1966,13 +2012,13 @@ exports[`SnapUIRenderer supports forms with fields 1`] = ` "alignItems": "center", "alignSelf": "stretch", "backgroundColor": "#ffffff", - "borderColor": "#BBC0C566", + "borderColor": "#b7bbc866", "borderRadius": 8, "borderWidth": 1, "flexDirection": "row", "height": "auto", "justifyContent": "center", - "maxHeight": 64, + "maxHeight": 58, "minHeight": 48, "paddingBottom": 8, "paddingHorizontal": 16, @@ -2031,12 +2077,12 @@ exports[`SnapUIRenderer supports forms with fields 1`] = ` ellipsizeMode="tail" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -2047,12 +2093,12 @@ exports[`SnapUIRenderer supports forms with fields 1`] = ` ellipsizeMode="tail" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -2078,12 +2124,12 @@ exports[`SnapUIRenderer supports forms with fields 1`] = ` ellipsizeMode="tail" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -2094,12 +2140,12 @@ exports[`SnapUIRenderer supports forms with fields 1`] = ` ellipsizeMode="tail" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -2108,7 +2154,7 @@ exports[`SnapUIRenderer supports forms with fields 1`] = ` - + - - + > + + + - - - - Select an option - - - - - - - - + + Select an option + + - + + + + + - + + + + CardTitle1 + + + CardDescription1 + + + - CardTitle1 + CardValue1 - CardDescription1 + CardExtra1 - - - CardValue1 - - - CardExtra1 - - - - - - + + + + + CardTitle2 + + + CardDescription2 + + + - CardTitle2 + CardValue2 - CardDescription2 + CardExtra2 - - - CardValue2 - - - CardExtra2 - - - - + + - - + + - - - Submit - + Submit - + @@ -2725,11 +2786,11 @@ exports[`SnapUIRenderer supports interactive inputs 1`] = ` @@ -2785,7 +2846,7 @@ exports[`SnapUIRenderer supports interactive inputs 1`] = ` { "alignItems": "center", "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 8, "borderWidth": 1, "flexDirection": "row", @@ -2804,6 +2865,8 @@ exports[`SnapUIRenderer supports interactive inputs 1`] = ` } > @@ -2895,21 +2958,31 @@ exports[`SnapUIRenderer supports the onCancel prop 1`] = ` > Hello world! @@ -2951,7 +3024,7 @@ exports[`SnapUIRenderer supports the onCancel prop 1`] = ` "alignItems": "center", "alignSelf": "flex-start", "backgroundColor": "transparent", - "borderColor": "#0376c9", + "borderColor": "#4459ff", "borderRadius": 24, "borderWidth": 1, "flex": 1, @@ -2966,12 +3039,12 @@ exports[`SnapUIRenderer supports the onCancel prop 1`] = ` accessibilityRole="text" style={ { - "color": "#0376c9", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#4459ff", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -2990,7 +3063,7 @@ exports[`SnapUIRenderer supports the onCancel prop 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#141618", + "backgroundColor": "#121314", "borderRadius": 24, "flex": 1, "flexDirection": "row", @@ -2999,14 +3072,13 @@ exports[`SnapUIRenderer supports the onCancel prop 1`] = ` "paddingHorizontal": 16, } } - textVariant="sBodyMDMedium" > @@ -3046,16 +3118,27 @@ exports[`SnapUIRenderer supports the onCancel prop 1`] = ` style={ { "color": "#ffffff", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > Foo diff --git a/app/components/Snaps/SnapUIRenderer/components/address.ts b/app/components/Snaps/SnapUIRenderer/components/address.ts index 8766939a878..0505fcd57d3 100644 --- a/app/components/Snaps/SnapUIRenderer/components/address.ts +++ b/app/components/Snaps/SnapUIRenderer/components/address.ts @@ -3,6 +3,7 @@ import { UIComponentFactory } from './types'; export const address: UIComponentFactory = ({ element: e, + textColor, }) => ({ element: 'SnapUIAddress', props: { @@ -11,5 +12,6 @@ export const address: UIComponentFactory = ({ truncate: e.props.truncate, displayName: e.props.displayName, avatar: e.props.avatar, + color: textColor, }, }); diff --git a/app/components/Snaps/SnapUIRenderer/components/banner.test.ts b/app/components/Snaps/SnapUIRenderer/components/banner.test.ts index 1c0219fc6d3..8ff0c84215e 100644 --- a/app/components/Snaps/SnapUIRenderer/components/banner.test.ts +++ b/app/components/Snaps/SnapUIRenderer/components/banner.test.ts @@ -39,17 +39,24 @@ describe('banner component', () => { children: [ { key: '4322bc9dfc78dd5fac77c48bc64efc877ae6265f8cc50c12a63fe3a62674e402_1', - element: 'RNText', + element: 'Text', props: { - color: 'inherit', + color: undefined, + variant: 'sBodyMD', + style: { + fontWeight: '400', + textAlign: 'left', + }, }, children: 'Test content', }, ], props: { - color: 'inherit', - fontWeight: 'normal', - textAlign: 'left', + color: undefined, + style: { + fontWeight: '400', + textAlign: 'left', + }, variant: 'sBodyMD', }, }, @@ -83,17 +90,24 @@ describe('banner component', () => { children: [ { key: '4322bc9dfc78dd5fac77c48bc64efc877ae6265f8cc50c12a63fe3a62674e402_2', - element: 'RNText', + element: 'Text', props: { - color: 'inherit', + color: undefined, + variant: 'sBodyMD', + style: { + fontWeight: '400', + textAlign: 'left', + }, }, children: 'Test content', }, ], props: { - color: 'inherit', - fontWeight: 'normal', - textAlign: 'left', + color: undefined, + style: { + fontWeight: '400', + textAlign: 'left', + }, variant: 'sBodyMD', }, }, @@ -104,4 +118,55 @@ describe('banner component', () => { }, }); }); + + it('removes empty title', () => { + const el: BannerElement = { + type: 'Banner', + props: { + title: '', + severity: 'info', + children: createTextElement('Test content'), + }, + key: null, + }; + + const result = banner({ element: el, ...defaultParams }); + + expect(result).toEqual({ + element: 'SnapUIBanner', + children: [ + { + element: 'Text', + key: 'mock-key', + children: [ + { + key: '4322bc9dfc78dd5fac77c48bc64efc877ae6265f8cc50c12a63fe3a62674e402_3', + element: 'Text', + props: { + color: undefined, + variant: 'sBodyMD', + style: { + fontWeight: '400', + textAlign: 'left', + }, + }, + children: 'Test content', + }, + ], + props: { + color: undefined, + variant: 'sBodyMD', + style: { + fontWeight: '400', + textAlign: 'left', + }, + }, + }, + ], + props: { + severity: 'Info', + title: null, + }, + }); + }); }); diff --git a/app/components/Snaps/SnapUIRenderer/components/banner.ts b/app/components/Snaps/SnapUIRenderer/components/banner.ts index 19547e0d9f0..f802d0a1e35 100644 --- a/app/components/Snaps/SnapUIRenderer/components/banner.ts +++ b/app/components/Snaps/SnapUIRenderer/components/banner.ts @@ -22,7 +22,8 @@ export const banner: UIComponentFactory = ({ mapToTemplate({ element: children as JSXElement, ...params }), ), props: { - title: e.props.title, + // The Banner component shows an empty title if we dont do this. + title: e.props.title.length > 0 ? e.props.title : null, severity: transformSeverity(e.props.severity), }, }); diff --git a/app/components/Snaps/SnapUIRenderer/components/bold.ts b/app/components/Snaps/SnapUIRenderer/components/bold.ts index 50413d9e0a2..0ebd5358610 100644 --- a/app/components/Snaps/SnapUIRenderer/components/bold.ts +++ b/app/components/Snaps/SnapUIRenderer/components/bold.ts @@ -16,7 +16,7 @@ export const bold: UIComponentFactory = ({ ), props: { variant: TextVariant.BodyMDBold, - color: 'inherit', + color: params.textColor, numberOfLines: 0, flexWrap: 'wrap', }, diff --git a/app/components/Snaps/SnapUIRenderer/components/box.test.ts b/app/components/Snaps/SnapUIRenderer/components/box.test.ts index c60690158aa..68130470a4a 100644 --- a/app/components/Snaps/SnapUIRenderer/components/box.test.ts +++ b/app/components/Snaps/SnapUIRenderer/components/box.test.ts @@ -40,15 +40,24 @@ describe('box UIComponentFactory', () => { children: [ { key: '4322bc9dfc78dd5fac77c48bc64efc877ae6265f8cc50c12a63fe3a62674e402_1', - element: 'RNText', + element: 'Text', children: 'Test content', - props: { color: 'inherit' }, + props: { + color: undefined, + variant: 'sBodyMD', + style: { + fontWeight: '400', + textAlign: 'left', + }, + }, }, ], props: { - color: 'inherit', - fontWeight: 'normal', - textAlign: 'left', + color: undefined, + style: { + fontWeight: '400', + textAlign: 'left', + }, variant: 'sBodyMD', }, }, diff --git a/app/components/Snaps/SnapUIRenderer/components/button.ts b/app/components/Snaps/SnapUIRenderer/components/button.ts index ce8093e4f22..a8e7acfc964 100644 --- a/app/components/Snaps/SnapUIRenderer/components/button.ts +++ b/app/components/Snaps/SnapUIRenderer/components/button.ts @@ -1,22 +1,26 @@ -import { - ButtonElement, - ButtonProps, - JSXElement, -} from '@metamask/snaps-sdk/jsx'; +import { ButtonElement, JSXElement } from '@metamask/snaps-sdk/jsx'; import { getJsxChildren } from '@metamask/snaps-utils'; import { NonEmptyArray } from '@metamask/utils'; import { mapTextToTemplate } from '../utils'; import { UIComponentFactory } from './types'; import { TextVariant } from '../../../../component-library/components/Texts/Text'; +import { Theme } from '../../../../util/theme/models'; -interface ButtonElementProps extends ButtonElement { - props: ButtonProps & { - loading?: boolean; - size?: 'sm' | 'md'; - }; +function getTextColor(theme: Theme, props: ButtonElement['props']) { + if (props.disabled) { + return theme.colors.text.muted; + } + + switch (props.variant) { + case 'destructive': + return theme.colors.error.default; + default: + case 'primary': + return theme.colors.info.default; + } } -export const button: UIComponentFactory = ({ +export const button: UIComponentFactory = ({ element: e, ...params }) => ({ @@ -29,13 +33,16 @@ export const button: UIComponentFactory = ({ name: e.props.name, disabled: e.props.disabled, loading: e.props.loading ?? false, - textVariant: - e.props.size === 'sm' - ? TextVariant.BodySMMedium - : TextVariant.BodyMDMedium, }, children: mapTextToTemplate( getJsxChildren(e) as NonEmptyArray, - params, + { + ...params, + textColor: getTextColor(params.theme, e.props), + textVariant: + e.props.size === 'sm' + ? TextVariant.BodySMMedium + : TextVariant.BodyMDMedium, + }, ), }); diff --git a/app/components/Snaps/SnapUIRenderer/components/card.test.ts b/app/components/Snaps/SnapUIRenderer/components/card.test.ts index 06dcf7867ad..bdf641e587c 100644 --- a/app/components/Snaps/SnapUIRenderer/components/card.test.ts +++ b/app/components/Snaps/SnapUIRenderer/components/card.test.ts @@ -58,6 +58,7 @@ describe('card component mapper', () => { "address": "0xab16a96D359eC26a11e2C2b3d8f8B8942d5Bfcdb", "avatar": undefined, "avatarSize": "xs", + "color": undefined, "displayName": undefined, "truncate": undefined, }, diff --git a/app/components/Snaps/SnapUIRenderer/components/container.test.ts b/app/components/Snaps/SnapUIRenderer/components/container.test.ts index 678ca60fa27..e148f04d79b 100644 --- a/app/components/Snaps/SnapUIRenderer/components/container.test.ts +++ b/app/components/Snaps/SnapUIRenderer/components/container.test.ts @@ -104,6 +104,7 @@ describe('container', () => { "props": { "isSnapAction": false, "onCancel": [MockFunction], + "variant": "Secondary", }, }, "element": "Box", diff --git a/app/components/Snaps/SnapUIRenderer/components/container.ts b/app/components/Snaps/SnapUIRenderer/components/container.ts index 12ae1fd82bd..9e0307afcd8 100644 --- a/app/components/Snaps/SnapUIRenderer/components/container.ts +++ b/app/components/Snaps/SnapUIRenderer/components/container.ts @@ -3,6 +3,7 @@ import { getJsxChildren } from '@metamask/snaps-utils'; import { mapToTemplate } from '../utils'; import { UIComponentFactory } from './types'; import { DEFAULT_FOOTER } from './footer'; +import { ButtonVariants } from '../../../../component-library/components/Buttons/Button'; export const container: UIComponentFactory = ({ element: e, @@ -39,6 +40,7 @@ export const container: UIComponentFactory = ({ key: 'default-button', props: { onCancel, + variant: ButtonVariants.Secondary, isSnapAction: false, }, children: t('navigation.close'), diff --git a/app/components/Snaps/SnapUIRenderer/components/field.ts b/app/components/Snaps/SnapUIRenderer/components/field.ts index 2726f671ff0..18a669feb83 100644 --- a/app/components/Snaps/SnapUIRenderer/components/field.ts +++ b/app/components/Snaps/SnapUIRenderer/components/field.ts @@ -10,6 +10,7 @@ import { getPrimaryChildElementIndex, mapToTemplate } from '../utils'; import { checkbox as checkboxFn } from './checkbox'; import { selector as selectorFn } from './selector'; import { UIComponentFactory, UIComponentParams } from './types'; +import { constructInputProps } from './input'; export const field: UIComponentFactory = ({ element: e, @@ -62,6 +63,7 @@ export const field: UIComponentFactory = ({ return { element: 'SnapUIInput', props: { + ...constructInputProps(input.props), id: input.props.name, placeholder: input.props.placeholder, label: e.props.label, diff --git a/app/components/Snaps/SnapUIRenderer/components/footer.test.ts b/app/components/Snaps/SnapUIRenderer/components/footer.test.ts index 74b3710bddf..8dbd4bb5221 100644 --- a/app/components/Snaps/SnapUIRenderer/components/footer.test.ts +++ b/app/components/Snaps/SnapUIRenderer/components/footer.test.ts @@ -59,16 +59,21 @@ describe('footer', () => { loading: false, name: undefined, onCancel: undefined, - textVariant: 'sBodyMDMedium', type: undefined, variant: 'Primary', }, children: [ { key: '57fd48ba929aa415dc4c3996c826a75f8686418c77765eb14fad2658efa73d87_1', - element: 'RNText', + element: 'Text', children: 'Button', - props: { color: 'inherit' }, + props: { + color: 'inherit', + style: { + fontWeight: undefined, + textAlign: undefined, + }, + }, }, ], }, diff --git a/app/components/Snaps/SnapUIRenderer/components/footer.ts b/app/components/Snaps/SnapUIRenderer/components/footer.ts index 215f580c072..77fece80155 100644 --- a/app/components/Snaps/SnapUIRenderer/components/footer.ts +++ b/app/components/Snaps/SnapUIRenderer/components/footer.ts @@ -1,9 +1,14 @@ -import { FooterElement, ButtonElement } from '@metamask/snaps-sdk/jsx'; +import { + FooterElement, + ButtonElement, + JSXElement, +} from '@metamask/snaps-sdk/jsx'; import { getJsxChildren } from '@metamask/snaps-utils'; -import { UIComponent, UIComponentFactory, UIComponentParams } from './types'; -import { button as buttonFn } from './button'; +import { UIComponent, UIComponentFactory } from './types'; import { TemplateConfirmation } from '../../SnapDialogApproval/SnapDialogApproval'; import { ButtonVariants } from '../../../../component-library/components/Buttons/Button'; +import { mapTextToTemplate } from '../utils'; +import { NonEmptyArray } from '@metamask/utils'; export const DEFAULT_FOOTER = { element: 'Box', @@ -58,20 +63,23 @@ export const footer: UIComponentFactory = ({ const footerChildren: UIComponent[] = ( providedChildren as ButtonElement[] - ).map((children, index) => { - const buttonMapped = buttonFn({ - ...params, - t, - element: children, - onCancel, - } as UIComponentParams); + ).map((child, index) => { + const textChildren = mapTextToTemplate( + getJsxChildren(child) as NonEmptyArray, + // We specifically use inherit here because we know this will be nested in colored Text. + { ...params, textColor: 'inherit' }, + ); return { element: 'SnapUIFooterButton', - key: `snap-footer-button-${buttonMapped.props?.name ?? index}`, + key: `snap-footer-button-${child.props?.name ?? index}`, props: { - ...buttonMapped.props, - snapVariant: buttonMapped.props?.variant, + form: child.props.form, + type: child.props.type, + name: child.props.name, + disabled: child.props.disabled, + loading: child.props.loading ?? false, + snapVariant: child.props.variant, variant: providedChildren.length === 2 && index === 0 ? ButtonVariants.Secondary @@ -79,7 +87,7 @@ export const footer: UIComponentFactory = ({ isSnapAction: true, onCancel, }, - children: buttonMapped.children, + children: textChildren, }; }); diff --git a/app/components/Snaps/SnapUIRenderer/components/icon.ts b/app/components/Snaps/SnapUIRenderer/components/icon.ts index ef3185eb9b8..acbb0198579 100644 --- a/app/components/Snaps/SnapUIRenderer/components/icon.ts +++ b/app/components/Snaps/SnapUIRenderer/components/icon.ts @@ -9,7 +9,10 @@ import { const ICON_NAMES = new Set(Object.values(IconName)); -export const icon: UIComponentFactory = ({ element }) => { +export const icon: UIComponentFactory = ({ + element, + textSize, +}) => { const getIconName = () => { const rawName = element.props.name; // The icon names are formatted differently between extension and mobile, @@ -36,7 +39,7 @@ export const icon: UIComponentFactory = ({ element }) => { }; const getIconSize = () => { - switch (element.props.size) { + switch (element.props.size ?? textSize) { case 'md': return IconSize.Md; default: diff --git a/app/components/Snaps/SnapUIRenderer/components/input.ts b/app/components/Snaps/SnapUIRenderer/components/input.ts index 1ed6a682193..f85f760d586 100644 --- a/app/components/Snaps/SnapUIRenderer/components/input.ts +++ b/app/components/Snaps/SnapUIRenderer/components/input.ts @@ -1,14 +1,40 @@ import { InputElement } from '@metamask/snaps-sdk/jsx'; +import { hasProperty } from '@metamask/utils'; import { UIComponentFactory } from './types'; -// TODO: Support min, max, type etc. +// For now the types only change what the input looks like. +// There is no special behavior for min, max, step etc. +export const constructInputProps = (props: InputElement['props']) => { + if (!hasProperty(props, 'type')) { + return {}; + } + + switch (props.type) { + case 'password': { + return { + secureTextEntry: true, + }; + } + + case 'number': { + return { + keyboardType: 'numeric', + }; + } + + default: + return {}; + } +}; + export const input: UIComponentFactory = ({ element: e, form, }) => ({ element: 'SnapUIInput', props: { + ...constructInputProps(e.props), id: e.props.name, placeholder: e.props.placeholder, disabled: e.props.disabled, diff --git a/app/components/Snaps/SnapUIRenderer/components/link.test.ts b/app/components/Snaps/SnapUIRenderer/components/link.test.ts index e9c2e5f75b6..efb3dfe28b2 100644 --- a/app/components/Snaps/SnapUIRenderer/components/link.test.ts +++ b/app/components/Snaps/SnapUIRenderer/components/link.test.ts @@ -25,11 +25,15 @@ describe('link component', () => { element: 'SnapUILink', children: [ { - element: 'RNText', + element: 'Text', children: 'link', key: expect.any(String), props: { - color: 'inherit', + color: '#4459ff', + style: { + fontWeight: undefined, + textAlign: undefined, + }, }, }, ], diff --git a/app/components/Snaps/SnapUIRenderer/components/link.ts b/app/components/Snaps/SnapUIRenderer/components/link.ts index b043c40d776..5473b2606f1 100644 --- a/app/components/Snaps/SnapUIRenderer/components/link.ts +++ b/app/components/Snaps/SnapUIRenderer/components/link.ts @@ -11,7 +11,7 @@ export const link: UIComponentFactory = ({ element: 'SnapUILink', children: mapTextToTemplate( getJsxChildren(e) as NonEmptyArray, - params, + { ...params, textColor: params.theme.colors.info.default }, ), props: { href: e.props.href, diff --git a/app/components/Snaps/SnapUIRenderer/components/text.test.ts b/app/components/Snaps/SnapUIRenderer/components/text.test.ts index d3763a02c21..4cc2ad266e6 100644 --- a/app/components/Snaps/SnapUIRenderer/components/text.test.ts +++ b/app/components/Snaps/SnapUIRenderer/components/text.test.ts @@ -31,16 +31,25 @@ describe('text component', () => { children: [ { key: 'ac37e9a8c31a35346c51f0f9058d2e2f0aecde724a0d7192561af5625000f3d1_1', - element: 'RNText', + element: 'Text', children: 'Hello World', - props: { color: 'inherit' }, + props: { + color: undefined, + variant: 'sBodyMD', + style: { + fontWeight: '400', + textAlign: 'left', + }, + }, }, ], props: { variant: TextVariant.BodyMD, - fontWeight: 'normal', - color: 'inherit', - textAlign: 'left', + color: undefined, + style: { + fontWeight: '400', + textAlign: 'left', + }, }, }); }); @@ -73,19 +82,15 @@ describe('text component', () => { }); it('should handle different font weights', () => { - const weights: TextElement['props']['fontWeight'][] = [ - 'bold', - 'medium', - 'regular', - ]; + const weights = ['bold', 'medium', 'regular'] as const; + const expectedWeights = { - bold: 'bold', - medium: 'medium', - regular: 'normal', + bold: '700', + medium: '500', + regular: '400', }; weights.forEach((weight) => { - if (!weight) return; const el: TextElement = { type: 'Text', props: { fontWeight: weight, children: ['Test'] }, @@ -93,18 +98,16 @@ describe('text component', () => { }; const result = text({ element: el, ...defaultParams }); - if (weight in expectedWeights) { - expect(result.props?.fontWeight).toBe(expectedWeights[weight]); - } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + expect((result.props as any)?.style?.fontWeight).toBe( + expectedWeights[weight], + ); }); }); it('should handle different text alignments', () => { - const alignments: TextElement['props']['alignment'][] = [ - 'start', - 'center', - 'end', - ]; + const alignments = ['start', 'center', 'end'] as const; + const expectedAlignments = { start: 'left', center: 'center', @@ -112,7 +115,6 @@ describe('text component', () => { }; alignments.forEach((alignment) => { - if (!alignment) return; const el: TextElement = { type: 'Text', props: { alignment, children: ['Test'] }, @@ -120,9 +122,10 @@ describe('text component', () => { }; const result = text({ element: el, ...defaultParams }); - if (alignment in expectedAlignments) { - expect(result.props?.textAlign).toBe(expectedAlignments[alignment]); - } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + expect((result.props as any)?.style?.textAlign).toBe( + expectedAlignments[alignment], + ); }); }); diff --git a/app/components/Snaps/SnapUIRenderer/components/text.ts b/app/components/Snaps/SnapUIRenderer/components/text.ts index e55dc2a7b94..770477a662b 100644 --- a/app/components/Snaps/SnapUIRenderer/components/text.ts +++ b/app/components/Snaps/SnapUIRenderer/components/text.ts @@ -7,6 +7,7 @@ import { TextColor, TextVariant, } from '../../../../component-library/components/Texts/Text/Text.types'; +import { typography } from '@metamask/design-tokens'; function getTextColor(color: TextElement['props']['color']) { switch (color) { @@ -23,23 +24,29 @@ function getTextColor(color: TextElement['props']['color']) { case 'warning': return TextColor.Warning; default: - return 'inherit'; + return null; } } -function getFontWeight(color: TextElement['props']['fontWeight']) { - switch (color) { +function getFontWeight( + color: TextElement['props']['fontWeight'], + inheritedWeight?: string, +) { + switch (color ?? inheritedWeight) { case 'bold': - return 'bold'; + return typography.sBodyMDBold.fontWeight; case 'medium': - return 'medium'; + return typography.sBodyMDMedium.fontWeight; case 'regular': default: - return 'normal'; + return typography.sBodyMD.fontWeight; } } -const alignText = (alignment: TextElement['props']['alignment']) => { +function getTextAlignment( + alignment: TextElement['props']['alignment'], + inheritedAlignment?: string, +) { switch (alignment) { case 'start': return 'left'; @@ -48,26 +55,58 @@ const alignText = (alignment: TextElement['props']['alignment']) => { case 'end': return 'right'; default: - return 'left'; + return inheritedAlignment ?? 'left'; } -}; +} + +function getTextVariant( + size: TextElement['props']['size'], + inheritedVariant?: string, +) { + switch (size) { + case 'md': + return TextVariant.BodyMD; + case 'sm': + return TextVariant.BodySM; + default: + return inheritedVariant ?? TextVariant.BodyMD; + } +} export const text: UIComponentFactory = ({ element: e, ...params -}) => ({ - element: 'Text', - children: mapTextToTemplate( - getJsxChildren(e) as NonEmptyArray, - { - size: e.props.size, - ...params, +}) => { + const textColor = getTextColor(e.props.color) ?? params.textColor; + const textVariant = getTextVariant(e.props.size, params.textVariant); + const textFontWeight = getFontWeight( + e.props.fontWeight, + params.textFontWeight, + ); + const textAlignment = getTextAlignment( + e.props.alignment, + params.textAlignment, + ); + return { + element: 'Text', + children: mapTextToTemplate( + getJsxChildren(e) as NonEmptyArray, + { + ...params, + textSize: e.props.size, + textColor, + textVariant, + textFontWeight, + textAlignment, + }, + ), + props: { + variant: textVariant, + color: textColor, + style: { + fontWeight: textFontWeight, + textAlign: textAlignment, + }, }, - ), - props: { - variant: e.props.size === 'sm' ? TextVariant.BodySM : TextVariant.BodyMD, - fontWeight: getFontWeight(e.props.fontWeight), - color: getTextColor(e.props.color), - textAlign: alignText(e.props.alignment), - }, -}); + }; +}; diff --git a/app/components/Snaps/SnapUIRenderer/components/tooltip.test.ts b/app/components/Snaps/SnapUIRenderer/components/tooltip.test.ts index 82f9a996b4e..500136d7c9d 100644 --- a/app/components/Snaps/SnapUIRenderer/components/tooltip.test.ts +++ b/app/components/Snaps/SnapUIRenderer/components/tooltip.test.ts @@ -33,18 +33,25 @@ describe('tooltip component', () => { element: 'Text', children: [ { - element: 'RNText', + element: 'Text', children: 'Hover me', props: { - color: 'inherit', + color: undefined, + variant: 'sBodyMD', + style: { + fontWeight: '400', + textAlign: 'left', + }, }, key: expect.any(String), }, ], props: { - color: 'inherit', - fontWeight: 'normal', - textAlign: 'left', + color: undefined, + style: { + fontWeight: '400', + textAlign: 'left', + }, variant: 'sBodyMD', }, key: expect.any(String), @@ -55,18 +62,25 @@ describe('tooltip component', () => { element: 'Text', children: [ { - element: 'RNText', + element: 'Text', children: 'Tooltip content', props: { - color: 'inherit', + color: undefined, + variant: 'sBodyMD', + style: { + fontWeight: '400', + textAlign: 'left', + }, }, key: expect.any(String), }, ], props: { - color: 'inherit', - fontWeight: 'normal', - textAlign: 'left', + color: undefined, + style: { + fontWeight: '400', + textAlign: 'left', + }, variant: 'sBodyMD', }, key: expect.any(String), @@ -97,18 +111,25 @@ describe('tooltip component', () => { element: 'Text', children: [ { - element: 'RNText', + element: 'Text', children: 'Hover me', props: { - color: 'inherit', + color: undefined, + variant: 'sBodyMD', + style: { + fontWeight: '400', + textAlign: 'left', + }, }, key: expect.any(String), }, ], props: { - color: 'inherit', - fontWeight: 'normal', - textAlign: 'left', + color: undefined, + style: { + fontWeight: '400', + textAlign: 'left', + }, variant: 'sBodyMD', }, key: expect.any(String), @@ -119,18 +140,25 @@ describe('tooltip component', () => { element: 'Text', children: [ { - element: 'RNText', + element: 'Text', children: 'Complex content', props: { - color: 'inherit', + color: undefined, + variant: 'sBodyMD', + style: { + fontWeight: '400', + textAlign: 'left', + }, }, key: expect.any(String), }, ], props: { - color: 'inherit', - fontWeight: 'normal', - textAlign: 'left', + color: undefined, + style: { + fontWeight: '400', + textAlign: 'left', + }, variant: 'sBodyMD', }, key: expect.any(String), @@ -161,18 +189,25 @@ describe('tooltip component', () => { element: 'Text', children: [ { - element: 'RNText', + element: 'Text', children: 'Nested text', props: { - color: 'inherit', + color: undefined, + variant: 'sBodyMD', + style: { + fontWeight: '400', + textAlign: 'left', + }, }, key: expect.any(String), }, ], props: { - color: 'inherit', - fontWeight: 'normal', - textAlign: 'left', + color: undefined, + style: { + fontWeight: '400', + textAlign: 'left', + }, variant: 'sBodyMD', }, key: expect.any(String), @@ -183,18 +218,25 @@ describe('tooltip component', () => { element: 'Text', children: [ { - element: 'RNText', + element: 'Text', children: 'Tooltip content', props: { - color: 'inherit', + color: undefined, + variant: 'sBodyMD', + style: { + fontWeight: '400', + textAlign: 'left', + }, }, key: expect.any(String), }, ], props: { - color: 'inherit', - fontWeight: 'normal', - textAlign: 'left', + color: undefined, + style: { + fontWeight: '400', + textAlign: 'left', + }, variant: 'sBodyMD', }, key: expect.any(String), diff --git a/app/components/Snaps/SnapUIRenderer/components/types.ts b/app/components/Snaps/SnapUIRenderer/components/types.ts index 76659b74cdf..76775dd336c 100644 --- a/app/components/Snaps/SnapUIRenderer/components/types.ts +++ b/app/components/Snaps/SnapUIRenderer/components/types.ts @@ -8,7 +8,15 @@ export interface UIComponentParams { useFooter?: boolean; onCancel?: () => void; t: (key: string) => string; + + // React Native specific props theme: Theme; + // If the component must inherit any of the following props from the parent, the parent must pass the props to its children. + textSize?: string; + textColor?: string; + textVariant?: string; + textFontWeight?: string; + textAlignment?: string; } export interface UIComponent { diff --git a/app/components/Snaps/SnapUIRenderer/utils.test.ts b/app/components/Snaps/SnapUIRenderer/utils.test.ts index 3100a79f7cf..6262cd7a39f 100644 --- a/app/components/Snaps/SnapUIRenderer/utils.test.ts +++ b/app/components/Snaps/SnapUIRenderer/utils.test.ts @@ -32,19 +32,26 @@ describe('SnapUIRenderer utils', () => { "children": [ { "children": "Test Content", - "element": "RNText", + "element": "Text", "key": "87ada83862ef4cde3ca2a1f8cbfbbc38af6f971cb4d669224ab903ffc2c7d1bd_2", "props": { - "color": "inherit", + "color": undefined, + "style": { + "fontWeight": "400", + "textAlign": "left", + }, + "variant": "sBodyMD", }, }, ], "element": "Text", "key": "87ada83862ef4cde3ca2a1f8cbfbbc38af6f971cb4d669224ab903ffc2c7d1bd_1", "props": { - "color": "inherit", - "fontWeight": "normal", - "textAlign": "left", + "color": undefined, + "style": { + "fontWeight": "400", + "textAlign": "left", + }, "variant": "sBodyMD", }, } @@ -75,7 +82,7 @@ describe('SnapUIRenderer utils', () => { const result = mapTextToTemplate([iconElement], { map: {}, theme: mockTheme, - size: 'sm', + textSize: 'sm', }); expect(result[0]).toMatchObject({ @@ -98,7 +105,7 @@ describe('SnapUIRenderer utils', () => { const result = mapTextToTemplate([textElement], { map: {}, theme: mockTheme, - size: 'sm', + textSize: 'sm', }); expect(result[0]).toMatchObject({ @@ -120,7 +127,7 @@ describe('SnapUIRenderer utils', () => { const result = mapTextToTemplate([iconElement], { map: {}, theme: mockTheme, - size: 'md', + textSize: 'md', }); expect(result[0]).toMatchObject({ diff --git a/app/components/Snaps/SnapUIRenderer/utils.ts b/app/components/Snaps/SnapUIRenderer/utils.ts index a7eb790c858..edb539ec624 100644 --- a/app/components/Snaps/SnapUIRenderer/utils.ts +++ b/app/components/Snaps/SnapUIRenderer/utils.ts @@ -1,5 +1,10 @@ -import { JSXElement, GenericSnapElement, Text } from '@metamask/snaps-sdk/jsx'; -import { hasChildren } from '@metamask/snaps-utils'; +import { + JSXElement, + GenericSnapElement, + Text, + InputElement, +} from '@metamask/snaps-sdk/jsx'; +import { getJsxChildren, hasChildren } from '@metamask/snaps-utils'; import { memoize } from 'lodash'; import { sha256 } from '@noble/hashes/sha256'; import { @@ -22,10 +27,38 @@ export interface MapToTemplateParams { onCancel?: () => void; onConfirm?: () => void; t?: (key: string) => string; + + // React Native specific props theme: Theme; - size?: string; + // If the component must inherit any of the following props from the parent, the parent must pass the props to its children. + textSize?: string; + textColor?: string; + textVariant?: string; + textFontWeight?: string; + textAlignment?: string; } +/** + * Registry of element types that are used within Field element. + */ +export const FIELD_ELEMENT_TYPES = [ + 'FileInput', + 'Input', + 'Dropdown', + 'RadioGroup', + 'Checkbox', + 'Selector', +]; + +/** + * Search for the element that is considered to be primary child element of a Field. + * + * @param children - Children elements specified within Field element. + * @returns Number, representing index of a primary field in the array of children elements. + */ +export const getPrimaryChildElementIndex = (children: JSXElement[]) => + children.findIndex((c) => FIELD_ELEMENT_TYPES.includes(c.type)); + /** * Get a truncated version of component children to use in a hash. * @@ -39,6 +72,14 @@ function getChildrenForHash(component: JSXElement) { const { children } = component.props; + // Field has special handling to determine the primary child to use for the key + if (component.type === 'Field') { + const fieldChildren = getJsxChildren(component) as JSXElement[]; + const primaryChildIndex = getPrimaryChildElementIndex(fieldChildren); + const primaryChild = fieldChildren[primaryChildIndex] as InputElement; + return { type: primaryChild?.type, name: primaryChild?.props?.name }; + } + if (typeof children === 'string') { // For the hash we reduce long strings return children.slice(0, 5000); @@ -130,7 +171,15 @@ export const mapTextToTemplate = ( elements: NonEmptyArray, params: Pick< MapToTemplateParams, - 'map' | 'useFooter' | 'onCancel' | 'theme' | 'size' + | 'map' + | 'useFooter' + | 'onCancel' + | 'theme' + | 'textSize' + | 'textColor' + | 'textVariant' + | 'textAlignment' + | 'textFontWeight' >, ): NonEmptyArray => elements.map((e) => { @@ -138,25 +187,21 @@ export const mapTextToTemplate = ( const text = unescapeFn(e); const key = generateKey(params.map, Text({ children: text })); return { - element: 'RNText', + element: 'Text', key, children: text, - props: { color: 'inherit' }, + props: { + variant: params.textVariant, + color: params.textColor, + style: { + fontWeight: params.textFontWeight, + textAlign: params.textAlignment, + }, + }, }; } - return mapToTemplate({ - ...params, - element: - e.type === 'Icon' - ? ({ - ...e, - props: { - size: params.size, - ...e.props, - }, - } as JSXElement) - : e, - }); + + return mapToTemplate({ ...params, element: e }); }) as NonEmptyArray; /** @@ -187,27 +232,6 @@ export const mergeValue = ( return { ...state, [name]: value }; }; -/** - * Registry of element types that are used within Field element. - */ -export const FIELD_ELEMENT_TYPES = [ - 'FileInput', - 'Input', - 'Dropdown', - 'RadioGroup', - 'Checkbox', - 'Selector', -]; - -/** - * Search for the element that is considered to be primary child element of a Field. - * - * @param children - Children elements specified within Field element. - * @returns Number, representing index of a primary field in the array of children elements. - */ -export const getPrimaryChildElementIndex = (children: JSXElement[]) => - children.findIndex((c) => FIELD_ELEMENT_TYPES.includes(c.type)); - /** * Map Snap custom size for border radius to mobile compatible size. * diff --git a/app/components/Snaps/SnapUISelector/SnapUISelector.styles.ts b/app/components/Snaps/SnapUISelector/SnapUISelector.styles.ts index 00ee4bf6a3b..628f3b79670 100644 --- a/app/components/Snaps/SnapUISelector/SnapUISelector.styles.ts +++ b/app/components/Snaps/SnapUISelector/SnapUISelector.styles.ts @@ -20,6 +20,7 @@ const styleSheet = (params: { theme: Theme }) => { minHeight: 300, paddingBottom: Device.isIphoneX() ? 20 : 0, overflow: 'hidden', + maxHeight: '80%', }, content: { paddingLeft: 16, @@ -29,7 +30,7 @@ const styleSheet = (params: { theme: Theme }) => { backgroundColor: colors.background.default, height: 'auto', minHeight: 48, - maxHeight: 64, + maxHeight: 58, borderColor: colors.border.muted, borderWidth: 1, borderRadius: 8, @@ -42,7 +43,7 @@ const styleSheet = (params: { theme: Theme }) => { backgroundColor: importedColors.transparent, height: 'auto', minHeight: 48, - maxHeight: 64, + maxHeight: 58, borderRadius: 8, paddingTop: 8, paddingBottom: 8, diff --git a/app/components/Snaps/SnapUISelector/SnapUISelector.tsx b/app/components/Snaps/SnapUISelector/SnapUISelector.tsx index 77c9f749831..4ad5a3c6ea6 100644 --- a/app/components/Snaps/SnapUISelector/SnapUISelector.tsx +++ b/app/components/Snaps/SnapUISelector/SnapUISelector.tsx @@ -119,7 +119,11 @@ export const SnapUISelector: React.FunctionComponent = ({ )} - + {title} diff --git a/app/components/Snaps/SnapUISpinner/SnapUISpinner.test.tsx b/app/components/Snaps/SnapUISpinner/SnapUISpinner.test.tsx index 1e1447bfe9f..2dde7401c07 100644 --- a/app/components/Snaps/SnapUISpinner/SnapUISpinner.test.tsx +++ b/app/components/Snaps/SnapUISpinner/SnapUISpinner.test.tsx @@ -2,13 +2,14 @@ import React from 'react'; import { ActivityIndicator } from 'react-native'; import { render } from '@testing-library/react-native'; import { SnapUISpinner } from './SnapUISpinner'; +import { lightTheme } from '@metamask/design-tokens'; const mockUseTheme = jest.fn(); jest.mock('../../../util/theme', () => ({ useTheme: () => mockUseTheme(), })); -const mockColor = '#0376c9'; +const mockColor = lightTheme.colors.primary.default; describe('SnapUISpinner', () => { beforeEach(() => { diff --git a/app/components/Snaps/SnapUITooltip/SnapUITooltip.test.tsx b/app/components/Snaps/SnapUITooltip/SnapUITooltip.test.tsx index 2c0357fb21f..c34c16ff5c5 100644 --- a/app/components/Snaps/SnapUITooltip/SnapUITooltip.test.tsx +++ b/app/components/Snaps/SnapUITooltip/SnapUITooltip.test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { fireEvent, render } from '@testing-library/react-native'; +import { fireEvent, render, waitFor } from '@testing-library/react-native'; import { SnapUITooltip } from './SnapUITooltip'; import { Text, TouchableOpacity } from 'react-native'; import ApprovalModal from '../../Approvals/ApprovalModal'; @@ -59,7 +59,9 @@ describe('SnapUITooltip', () => { await new Promise((resolve) => setTimeout(resolve, 0)); const modal = UNSAFE_getByType(ApprovalModal); - expect(modal.props.isVisible).toBe(false); + await waitFor(() => { + expect(modal.props.isVisible).toBe(false); + }); }); it('should render complex content in modal', () => { diff --git a/app/components/Snaps/SnapUITooltip/SnapUITooltip.tsx b/app/components/Snaps/SnapUITooltip/SnapUITooltip.tsx index 3b0e15d9fbe..ec79f58367b 100644 --- a/app/components/Snaps/SnapUITooltip/SnapUITooltip.tsx +++ b/app/components/Snaps/SnapUITooltip/SnapUITooltip.tsx @@ -29,7 +29,7 @@ export const SnapUITooltip: FunctionComponent = ({ return ( <> {children} - + {content} diff --git a/app/components/UI/AccountApproval/__snapshots__/index.test.tsx.snap b/app/components/UI/AccountApproval/__snapshots__/index.test.tsx.snap index bd879ef62ca..2991278affe 100644 --- a/app/components/UI/AccountApproval/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/AccountApproval/__snapshots__/index.test.tsx.snap @@ -34,7 +34,7 @@ exports[`AccountApproval should render correctly 1`] = ` @@ -343,19 +343,19 @@ exports[`AccountApproval should render correctly 1`] = ` style={ { "0": { - "color": "#141618", + "color": "#121314", "flexGrow": 1, - "fontFamily": "EuclidCircularB-Bold", + "fontFamily": "CentraNo1-Bold", "fontSize": 16, "fontWeight": "600", }, "1": undefined, - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -371,18 +371,18 @@ exports[`AccountApproval should render correctly 1`] = ` { "0": { "alignSelf": "flex-start", - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", + "color": "#121314", + "fontFamily": "CentraNo1-Book", "fontSize": 14, "fontWeight": "100", }, "1": undefined, - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -418,7 +418,7 @@ exports[`AccountApproval should render correctly 1`] = ` }, { "backgroundColor": "#ffffff", - "borderColor": "#6a737d", + "borderColor": "#686e7d", "borderWidth": 1, }, [ @@ -447,13 +447,13 @@ exports[`AccountApproval should render correctly 1`] = ` null, [ { - "fontFamily": "EuclidCircularB-Bold", + "fontFamily": "CentraNo1-Bold", "fontSize": 14, "fontWeight": "600", "textAlign": "center", }, { - "color": "#6a737d", + "color": "#686e7d", }, undefined, ], @@ -479,7 +479,7 @@ exports[`AccountApproval should render correctly 1`] = ` "padding": 15, }, { - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "minHeight": 50, }, [ @@ -509,7 +509,7 @@ exports[`AccountApproval should render correctly 1`] = ` null, [ { - "fontFamily": "EuclidCircularB-Bold", + "fontFamily": "CentraNo1-Bold", "fontSize": 14, "fontWeight": "600", "textAlign": "center", diff --git a/app/components/UI/AccountApproval/index.js b/app/components/UI/AccountApproval/index.js index 7e55be10c09..948d3fa123c 100644 --- a/app/components/UI/AccountApproval/index.js +++ b/app/components/UI/AccountApproval/index.js @@ -19,7 +19,6 @@ import { CommonSelectorsIDs } from '../../../../e2e/selectors/Common.selectors'; import { ConnectAccountBottomSheetSelectorsIDs } from '../../../../e2e/selectors/Browser/ConnectAccountBottomSheet.selectors'; import { withMetricsAwareness } from '../../../components/hooks/useMetrics'; import Routes from '../../../constants/navigation/Routes'; -import Engine from '../../../core/Engine'; import SDKConnect from '../../../core/SDKConnect/SDKConnect'; import { selectAccountsLength } from '../../../selectors/accountTrackerController'; import { selectSelectedInternalAccountFormattedAddress } from '../../../selectors/accountsController'; @@ -36,6 +35,7 @@ import ShowWarningBanner from './showWarningBanner'; import createStyles from './styles'; import { SourceType } from '../../hooks/useMetrics/useMetrics.types'; import { MetricsEventBuilder } from '../../../core/Analytics/MetricsEventBuilder'; +import { getPhishingTestResult } from '../../../util/phishingDetection'; /** * Account access approval component @@ -286,12 +286,9 @@ class AccountApproval extends PureComponent { }; checkUrlFlaggedAsPhishing = (hostname) => { - const { PhishingController } = Engine.context; - PhishingController.maybeUpdateState(); - const phishingControllerTestResult = PhishingController.test(hostname); - + const phishingResult = getPhishingTestResult(hostname); this.setState({ - isUrlFlaggedAsPhishing: phishingControllerTestResult.result, + isUrlFlaggedAsPhishing: phishingResult?.result || false, }); }; diff --git a/app/components/UI/AccountApproval/index.test.tsx b/app/components/UI/AccountApproval/index.test.tsx index 29e438ead16..66cac620a6d 100644 --- a/app/components/UI/AccountApproval/index.test.tsx +++ b/app/components/UI/AccountApproval/index.test.tsx @@ -34,6 +34,14 @@ jest.mock('../../../core/Engine', () => { }; }); +jest.mock('../../../util/phishingDetection', () => ({ + getPhishingTestResult: jest.fn((url) => { + if (url === 'phishing.com') return { result: true }; + return { result: false }; + }), + isProductSafetyDappScanningEnabled: jest.fn().mockReturnValue(false), +})); + const mockInitialState = { engine: { backgroundState: { diff --git a/app/components/UI/AccountApproval/styles.ts b/app/components/UI/AccountApproval/styles.ts index 1a175076f20..904377af371 100644 --- a/app/components/UI/AccountApproval/styles.ts +++ b/app/components/UI/AccountApproval/styles.ts @@ -1,6 +1,10 @@ import { StyleSheet } from 'react-native'; import Device from '../../../util/device'; import type { ThemeColors, ThemeTypography } from '@metamask/design-tokens'; +import { + getFontFamily, + TextVariant, +} from '../../../component-library/components/Texts/Text'; const createStyles = (colors: ThemeColors, typography: ThemeTypography) => StyleSheet.create({ @@ -17,6 +21,7 @@ const createStyles = (colors: ThemeColors, typography: ThemeTypography) => }, intro: { ...typography.sHeadingMD, + fontFamily: getFontFamily(TextVariant.HeadingMD), textAlign: 'center', color: colors.text.default, marginBottom: 8, @@ -24,6 +29,7 @@ const createStyles = (colors: ThemeColors, typography: ThemeTypography) => }, intro_reconnect: { ...typography.sHeadingMD, + fontFamily: getFontFamily(TextVariant.HeadingMD), textAlign: 'center', color: colors.text.default, marginBottom: 8, @@ -40,6 +46,7 @@ const createStyles = (colors: ThemeColors, typography: ThemeTypography) => }, warning: { ...typography.sHeadingSMRegular, + fontFamily: getFontFamily(TextVariant.HeadingSMRegular), color: colors.text.default, paddingHorizontal: 24, marginBottom: 16, @@ -110,7 +117,8 @@ const createStyles = (colors: ThemeColors, typography: ThemeTypography) => borderColor: colors.primary.default, }, optionText: { - ...typography.lBodyMD, + ...typography.sBodyMD, + fontFamily: getFontFamily(TextVariant.BodyMD), color: colors.text.default, marginHorizontal: 1, }, diff --git a/app/components/UI/AccountFromToInfoCard/__snapshots__/AccountFromToInfoCard.test.tsx.snap b/app/components/UI/AccountFromToInfoCard/__snapshots__/AccountFromToInfoCard.test.tsx.snap index 865f7651a7f..a3caa4b8dfb 100644 --- a/app/components/UI/AccountFromToInfoCard/__snapshots__/AccountFromToInfoCard.test.tsx.snap +++ b/app/components/UI/AccountFromToInfoCard/__snapshots__/AccountFromToInfoCard.test.tsx.snap @@ -23,12 +23,12 @@ exports[`AccountFromToInfoCard should match snapshot 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", + "color": "#121314", + "fontFamily": "CentraNo1-Book", "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -39,7 +39,7 @@ exports[`AccountFromToInfoCard should match snapshot 1`] = ` style={ { "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 4, "borderWidth": 1, "flexDirection": "row", @@ -269,7 +269,7 @@ exports[`AccountFromToInfoCard should match snapshot 1`] = ` "height": 32, "justifyContent": "center", "overflow": "hidden", - "shadowColor": "#0000001A", + "shadowColor": "#0000001a", "shadowOffset": { "height": 2, "width": 0, @@ -306,12 +306,12 @@ exports[`AccountFromToInfoCard should match snapshot 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > @@ -330,12 +330,12 @@ exports[`AccountFromToInfoCard should match snapshot 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Bold", + "fontSize": 16, "fontWeight": "700", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -349,12 +349,12 @@ exports[`AccountFromToInfoCard should match snapshot 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, "marginLeft": "auto", } } @@ -365,12 +365,12 @@ exports[`AccountFromToInfoCard should match snapshot 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Bold", + "fontSize": 16, "fontWeight": "700", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -407,12 +407,12 @@ exports[`AccountFromToInfoCard should match snapshot 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", + "color": "#121314", + "fontFamily": "CentraNo1-Book", "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -433,7 +433,7 @@ exports[`AccountFromToInfoCard should match snapshot 1`] = ` "paddingHorizontal": 10, }, { - "borderColor": "#848c96", + "borderColor": "#b7bbc8", }, ] } @@ -451,7 +451,7 @@ exports[`AccountFromToInfoCard should match snapshot 1`] = ` @@ -565,12 +565,12 @@ exports[`AccountFromToInfoCard should match snapshot 1`] = ` numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", "fontSize": 12, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -588,7 +588,7 @@ exports[`AccountFromToInfoCard should match snapshot 1`] = ` style={ [ { - "color": "#1c8234", + "color": "#1c7e33", "fontSize": 15, }, undefined, diff --git a/app/components/UI/AccountInfoCard/__snapshots__/index.test.tsx.snap b/app/components/UI/AccountInfoCard/__snapshots__/index.test.tsx.snap index 707e9f509e6..64cf9e67071 100644 --- a/app/components/UI/AccountInfoCard/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/AccountInfoCard/__snapshots__/index.test.tsx.snap @@ -5,7 +5,7 @@ exports[`AccountInfoCard should match snapshot 1`] = ` style={ { "alignItems": "center", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 10, "borderWidth": 1, "flexDirection": "row", @@ -17,7 +17,7 @@ exports[`AccountInfoCard should match snapshot 1`] = ` @@ -240,19 +240,19 @@ exports[`AccountInfoCard should match snapshot 1`] = ` style={ { "0": { - "color": "#141618", + "color": "#121314", "flexGrow": 1, - "fontFamily": "EuclidCircularB-Bold", + "fontFamily": "CentraNo1-Bold", "fontSize": 16, "fontWeight": "600", }, "1": undefined, - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -268,18 +268,18 @@ exports[`AccountInfoCard should match snapshot 1`] = ` { "0": { "alignSelf": "flex-start", - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", + "color": "#121314", + "fontFamily": "CentraNo1-Book", "fontSize": 14, "fontWeight": "100", }, "1": undefined, - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > diff --git a/app/components/UI/AccountInfoCard/index.js b/app/components/UI/AccountInfoCard/index.js index f6fb293df48..30b4d468412 100644 --- a/app/components/UI/AccountInfoCard/index.js +++ b/app/components/UI/AccountInfoCard/index.js @@ -29,7 +29,7 @@ import { getNormalizedTxState, getTicker, } from '../../../util/transactions'; -import ApproveTransactionHeader from '../../Views/confirmations/components/ApproveTransactionHeader'; +import ApproveTransactionHeader from '../../Views/confirmations/legacy/components/ApproveTransactionHeader'; import Identicon from '../Identicon'; import { selectInternalAccounts } from '../../../selectors/accountsController'; diff --git a/app/components/UI/AccountOverview/__snapshots__/index.test.tsx.snap b/app/components/UI/AccountOverview/__snapshots__/index.test.tsx.snap index 603b0d0074f..472dc69afd5 100644 --- a/app/components/UI/AccountOverview/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/AccountOverview/__snapshots__/index.test.tsx.snap @@ -35,7 +35,7 @@ exports[`AccountOverview should render correctly 1`] = ` onPress={[Function]} style={ { - "borderColor": "#0376c9", + "borderColor": "#4459ff", "borderRadius": 80, "borderWidth": 2, "padding": 2, @@ -46,7 +46,7 @@ exports[`AccountOverview should render correctly 1`] = ` ({ }), })); +// Mock useAccounts +jest.mock('../../../components/hooks/useAccounts', () => ({ + useAccounts: jest.fn().mockImplementation(() => ({ + accounts: [ + { + name: 'Account 1', + address: '0xC4955C0d639D99699Bfd7Ec54d9FaFEe40e4D272', + assets: { + fiatBalance: '$3200.00\n1 ETH', + }, + type: 'HD Key Tree', + yOffset: 0, + isSelected: true, + balanceError: undefined, + }, + { + name: 'Account 2', + address: '0xd018538C87232FF95acbCe4870629b75640a78E7', + assets: { + fiatBalance: '$6400.00\n2 ETH', + }, + type: 'HD Key Tree', + yOffset: 78, + isSelected: false, + balanceError: undefined, + }, + ], + evmAccounts: [], + ensByAccountAddress: {}, + })), +})); + // Mock Engine jest.mock('../../../core/Engine', () => ({ context: { @@ -106,6 +137,36 @@ const onRemoveImportedAccount = jest.fn(); const AccountSelectorListUseAccounts: React.FC = ({ privacyMode = false, }) => { + if (privacyMode) { + (useAccounts as jest.Mock).mockImplementationOnce(() => ({ + accounts: [ + { + name: 'Account 1', + address: '0xC4955C0d639D99699Bfd7Ec54d9FaFEe40e4D272', + assets: { + fiatBalance: '$3200.00\n1 ETH', + }, + type: 'HD Key Tree', + yOffset: 0, + isSelected: true, + balanceError: undefined, + }, + { + name: 'Account 2', + address: '0xd018538C87232FF95acbCe4870629b75640a78E7', + assets: { + fiatBalance: '$6400.00\n2 ETH', + }, + type: 'HD Key Tree', + yOffset: 78, + isSelected: false, + balanceError: undefined, + }, + ], + evmAccounts: [], + ensByAccountAddress: {}, + })); + } const { accounts, ensByAccountAddress } = useAccounts(); return ( { beforeEach(() => { - jest.spyOn(Utils, 'getAccountBalances').mockReturnValueOnce({ - balanceETH: '1', - balanceFiat: '$3200.00', - balanceWeiHex: '', - }); - jest.spyOn(Utils, 'getAccountBalances').mockReturnValueOnce({ - balanceETH: '2', - balanceFiat: '$6400.00', - balanceWeiHex: '', - }); onSelectAccount.mockClear(); onRemoveImportedAccount.mockClear(); }); @@ -193,38 +244,6 @@ describe('AccountSelectorList', () => { }); }); - it('should render all accounts but only the balance for selected account', async () => { - const { queryByTestId, getAllByTestId, toJSON } = renderComponent({ - engine: { - ...initialState.engine, - backgroundState: { - ...initialState.engine.backgroundState, - PreferencesController: { - ...initialState.engine.backgroundState.PreferencesController, - isMultiAccountBalancesEnabled: false, - }, - AccountsController: MOCK_ACCOUNTS_CONTROLLER_STATE, - }, - }, - }); - - await waitFor(async () => { - const accounts = getAllByTestId(regex.accountBalance); - expect(accounts.length).toBe(1); - - const businessAccountItem = await queryByTestId( - `${AccountListBottomSheetSelectorsIDs.ACCOUNT_BALANCE_BY_ADDRESS_TEST_ID}-${BUSINESS_ACCOUNT}`, - ); - - expect(within(businessAccountItem).getByText(regex.eth(1))).toBeDefined(); - expect( - within(businessAccountItem).getByText(regex.usd(3200)), - ).toBeDefined(); - - expect(toJSON()).toMatchSnapshot(); - }); - }); - it('renders all accounts with right accessory', async () => { const { getAllByTestId, toJSON } = renderComponent( initialState, @@ -315,6 +334,7 @@ describe('AccountSelectorList', () => { }); it('allows account removal for simple keyring type', async () => { const mockAlert = jest.spyOn(Alert, 'alert'); + mockAlert.mockReset(); mockAlert.mockImplementation( (_title, _message, buttons?: AlertButton[]) => { // Simulate user clicking "Yes, remove it" @@ -322,6 +342,25 @@ describe('AccountSelectorList', () => { }, ); + // Mock account data for a simple keyring account + (useAccounts as jest.Mock).mockImplementationOnce(() => ({ + accounts: [ + { + name: 'Account 1', + address: BUSINESS_ACCOUNT, + assets: { + fiatBalance: '$3200.00\n1 ETH', + }, + type: KeyringTypes.simple, // Important: must be simple type for removal + yOffset: 0, + isSelected: true, + balanceError: undefined, + }, + ], + evmAccounts: [], + ensByAccountAddress: {}, + })); + // Create a state with a simple keyring account const mockAccountsWithSimple = createMockAccountsControllerState([ BUSINESS_ACCOUNT, @@ -362,22 +401,23 @@ describe('AccountSelectorList', () => { expect.any(Array), { cancelable: false }, ); + }); - // Verify onRemoveImportedAccount was called with correct parameters - expect(onRemoveImportedAccount).toHaveBeenCalledWith({ - removedAddress: BUSINESS_ACCOUNT, - }); - - // Verify KeyringController.removeAccount was called - expect( - Engine.context.KeyringController.removeAccount, - ).toHaveBeenCalledWith(BUSINESS_ACCOUNT); + // Verify onRemoveImportedAccount was called with correct parameters + expect(onRemoveImportedAccount).toHaveBeenCalledWith({ + removedAddress: BUSINESS_ACCOUNT, }); + // Verify KeyringController.removeAccount was called + expect(Engine.context.KeyringController.removeAccount).toHaveBeenCalledWith( + BUSINESS_ACCOUNT, + ); + mockAlert.mockRestore(); }); it('allows account removal for snap keyring type', async () => { const mockAlert = jest.spyOn(Alert, 'alert'); + mockAlert.mockReset(); mockAlert.mockImplementation( (_title, _message, buttons?: AlertButton[]) => { // Simulate user clicking "Yes, remove it" @@ -385,6 +425,36 @@ describe('AccountSelectorList', () => { }, ); + // Mock account data for a snap account + (useAccounts as jest.Mock).mockImplementationOnce(() => ({ + accounts: [ + { + name: 'Snap Account 1', + address: MOCK_ADDRESS_1, + assets: { + fiatBalance: '$3200.00\n1 ETH', + }, + type: KeyringTypes.snap, // Important: must be snap type for removal + yOffset: 0, + isSelected: true, + balanceError: undefined, + }, + { + name: 'Snap Account 2', + address: MOCK_ADDRESS_2, + assets: { + fiatBalance: '$6400.00\n2 ETH', + }, + type: KeyringTypes.snap, // Important: must be snap type for removal + yOffset: 78, + isSelected: false, + balanceError: undefined, + }, + ], + evmAccounts: [], + ensByAccountAddress: {}, + })); + const mockAccountsWithSnap = createMockAccountsControllerStateWithSnap( [MOCK_ADDRESS_1, MOCK_ADDRESS_2], 'MetaMask Simple Snap Keyring', @@ -408,6 +478,7 @@ describe('AccountSelectorList', () => { // Trigger long press on the first cell that should correspond to MOCK_ADDRESS_1 cells[0].props.onLongPress(); + // Need to wait for the Alert to be called await waitFor(() => { // Verify Alert was shown with correct text expect(mockAlert).toHaveBeenCalledWith( @@ -416,19 +487,19 @@ describe('AccountSelectorList', () => { expect.any(Array), { cancelable: false }, ); + }); - // Verify onRemoveImportedAccount was called with correct parameters - expect(onRemoveImportedAccount).toHaveBeenCalledWith({ - removedAddress: MOCK_ADDRESS_1, - nextActiveAddress: MOCK_ADDRESS_2, - }); - - // Verify KeyringController.removeAccount was called - expect( - Engine.context.KeyringController.removeAccount, - ).toHaveBeenCalledWith(MOCK_ADDRESS_1); + // Verify onRemoveImportedAccount was called with correct parameters + expect(onRemoveImportedAccount).toHaveBeenCalledWith({ + removedAddress: MOCK_ADDRESS_1, + nextActiveAddress: MOCK_ADDRESS_2, }); + // Verify KeyringController.removeAccount was called + expect(Engine.context.KeyringController.removeAccount).toHaveBeenCalledWith( + MOCK_ADDRESS_1, + ); + mockAlert.mockRestore(); }); }); diff --git a/app/components/UI/AccountSelectorList/__snapshots__/AccountSelector.test.tsx.snap b/app/components/UI/AccountSelectorList/__snapshots__/AccountSelector.test.tsx.snap index c4498419f07..2d2c57dd0af 100644 --- a/app/components/UI/AccountSelectorList/__snapshots__/AccountSelector.test.tsx.snap +++ b/app/components/UI/AccountSelectorList/__snapshots__/AccountSelector.test.tsx.snap @@ -61,7 +61,7 @@ exports[`AccountSelectorList renders all accounts with balances 1`] = ` style={ { "alignItems": "center", - "backgroundColor": "#0376C91A", + "backgroundColor": "#4459ff1a", "flexDirection": "row", } } @@ -269,8 +269,8 @@ exports[`AccountSelectorList renders all accounts with balances 1`] = ` numberOfLines={1} style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", + "color": "#121314", + "fontFamily": "CentraNo1-Book", "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, @@ -314,12 +314,12 @@ exports[`AccountSelectorList renders all accounts with balances 1`] = ` numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -347,12 +347,12 @@ exports[`AccountSelectorList renders all accounts with balances 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, "textAlign": "right", } } @@ -363,12 +363,12 @@ exports[`AccountSelectorList renders all accounts with balances 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, "textAlign": "right", } } @@ -385,7 +385,7 @@ exports[`AccountSelectorList renders all accounts with balances 1`] = ` accessible={true} style={ { - "backgroundColor": "#0376C91A", + "backgroundColor": "#4459ff1a", "bottom": 0, "flexDirection": "row", "left": 0, @@ -399,7 +399,7 @@ exports[`AccountSelectorList renders all accounts with balances 1`] = ` @@ -747,12 +747,12 @@ exports[`AccountSelectorList renders all accounts with balances 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, "textAlign": "right", } } @@ -763,12 +763,12 @@ exports[`AccountSelectorList renders all accounts with balances 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, "textAlign": "right", } } @@ -809,7 +809,7 @@ exports[`AccountSelectorList renders all accounts with balances 1`] = ` testID="main-wallet-account-actions-1" > @@ -1201,7 +1201,7 @@ exports[`AccountSelectorList renders all accounts with right accessory 1`] = ` testID="main-wallet-account-actions-0" > @@ -1537,7 +1537,7 @@ exports[`AccountSelectorList renders all accounts with right accessory 1`] = ` testID="main-wallet-account-actions-1" > @@ -1903,12 +1903,12 @@ exports[`AccountSelectorList renders correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, "textAlign": "right", } } @@ -1919,12 +1919,12 @@ exports[`AccountSelectorList renders correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, "textAlign": "right", } } @@ -1941,7 +1941,7 @@ exports[`AccountSelectorList renders correctly 1`] = ` accessible={true} style={ { - "backgroundColor": "#0376C91A", + "backgroundColor": "#4459ff1a", "bottom": 0, "flexDirection": "row", "left": 0, @@ -1955,7 +1955,7 @@ exports[`AccountSelectorList renders correctly 1`] = ` @@ -2303,12 +2303,12 @@ exports[`AccountSelectorList renders correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, "textAlign": "right", } } @@ -2319,12 +2319,12 @@ exports[`AccountSelectorList renders correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, "textAlign": "right", } } @@ -2365,550 +2365,7 @@ exports[`AccountSelectorList renders correctly 1`] = ` testID="main-wallet-account-actions-1" > - - - - - - -`; - -exports[`AccountSelectorList should render all accounts but only the balance for selected account 1`] = ` - - - - - - - - - - - - - - Account 1 - - - - 0xC495...D272 - - - - - - - $3200.00 - - - 1 ETH - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Account 2 - - - - 0xd018...78E7 - - - - - - - - - - @@ -124,7 +124,7 @@ exports[`AddCustomToken render matches previous snapshot 1`] = ` onPress={[Function]} style={ { - "color": "#0376c9", + "color": "#4459ff", } } suppressHighlighting={true} @@ -144,8 +144,8 @@ exports[`AddCustomToken render matches previous snapshot 1`] = ` diff --git a/app/components/UI/AddCustomToken/index.js b/app/components/UI/AddCustomToken/index.js index 1a8e9b8913d..9fe0e084419 100644 --- a/app/components/UI/AddCustomToken/index.js +++ b/app/components/UI/AddCustomToken/index.js @@ -42,6 +42,7 @@ import Banner, { BannerVariant, } from '../../../component-library/components/Banners/Banner'; import CLText from '../../../component-library/components/Texts/Text/Text'; +import Logger from '../../../util/Logger'; const createStyles = (colors) => StyleSheet.create({ @@ -165,7 +166,7 @@ class AddCustomToken extends PureComponent { metrics: PropTypes.object, }; - getAnalyticsParams = () => { + getTokenAddedAnalyticsParams = () => { try { const { chainId } = this.props; const { address, symbol } = this.state; @@ -176,7 +177,8 @@ class AddCustomToken extends PureComponent { source: 'Custom token', }; } catch (error) { - return {}; + Logger.error(error, 'AddCustomToken.getTokenAddedAnalyticsParams error'); + return undefined; } }; @@ -186,12 +188,16 @@ class AddCustomToken extends PureComponent { const { address, symbol, decimals, name } = this.state; await TokensController.addToken({ address, symbol, decimals, name }); - this.props.metrics.trackEvent( - this.props.metrics - .createEventBuilder(MetaMetricsEvents.TOKEN_ADDED) - .addProperties(this.getAnalyticsParams()) - .build(), - ); + const analyticsParams = this.getTokenAddedAnalyticsParams(); + + if (analyticsParams) { + this.props.metrics.trackEvent( + this.props.metrics + .createEventBuilder(MetaMetricsEvents.TOKEN_ADDED) + .addProperties(analyticsParams) + .build(), + ); + } // Clear state before closing this.setState( diff --git a/app/components/UI/AddressInputs/__snapshots__/index.test.jsx.snap b/app/components/UI/AddressInputs/__snapshots__/index.test.jsx.snap index 9cdcbdd7409..99c38383400 100644 --- a/app/components/UI/AddressInputs/__snapshots__/index.test.jsx.snap +++ b/app/components/UI/AddressInputs/__snapshots__/index.test.jsx.snap @@ -23,12 +23,12 @@ exports[`AddressInputs AddressFrom should match default snapshot 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", + "color": "#121314", + "fontFamily": "CentraNo1-Book", "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -39,7 +39,7 @@ exports[`AddressInputs AddressFrom should match default snapshot 1`] = ` style={ [ { - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 8, "borderWidth": 1, "flex": 1, @@ -50,7 +50,7 @@ exports[`AddressInputs AddressFrom should match default snapshot 1`] = ` "padding": 10, }, { - "borderColor": "#848c96", + "borderColor": "#b7bbc8", }, ] } @@ -66,7 +66,7 @@ exports[`AddressInputs AddressFrom should match default snapshot 1`] = ` @@ -165,12 +165,12 @@ exports[`AddressInputs AddressFrom should match default snapshot 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", "fontSize": 12, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -204,12 +204,12 @@ exports[`AddressInputs AddressFrom should match snapshot when layout is vertical accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", + "color": "#121314", + "fontFamily": "CentraNo1-Book", "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -220,7 +220,7 @@ exports[`AddressInputs AddressFrom should match snapshot when layout is vertical style={ [ { - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 8, "borderWidth": 1, "flex": 1, @@ -231,7 +231,7 @@ exports[`AddressInputs AddressFrom should match snapshot when layout is vertical "padding": 10, }, { - "borderColor": "#848c96", + "borderColor": "#b7bbc8", }, ] } @@ -247,7 +247,7 @@ exports[`AddressInputs AddressFrom should match snapshot when layout is vertical @@ -346,12 +346,12 @@ exports[`AddressInputs AddressFrom should match snapshot when layout is vertical accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", "fontSize": 12, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -387,12 +387,12 @@ exports[`AddressInputs AddressTo should match default snapshot 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", + "color": "#121314", + "fontFamily": "CentraNo1-Book", "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -413,7 +413,7 @@ exports[`AddressInputs AddressTo should match default snapshot 1`] = ` "paddingHorizontal": 10, }, { - "borderColor": "#848c96", + "borderColor": "#b7bbc8", }, ] } @@ -436,7 +436,7 @@ exports[`AddressInputs AddressTo should match default snapshot 1`] = ` @@ -582,12 +582,12 @@ exports[`AddressInputs AddressTo should match default snapshot 1`] = ` numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", "fontSize": 12, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -605,7 +605,7 @@ exports[`AddressInputs AddressTo should match default snapshot 1`] = ` style={ [ { - "color": "#1c8234", + "color": "#1c7e33", "fontSize": 15, }, undefined, @@ -658,12 +658,12 @@ exports[`AddressInputs AddressTo should match snapshot when layout is vertical 1 accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", + "color": "#121314", + "fontFamily": "CentraNo1-Book", "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -684,7 +684,7 @@ exports[`AddressInputs AddressTo should match snapshot when layout is vertical 1 "paddingHorizontal": 10, }, { - "borderColor": "#848c96", + "borderColor": "#b7bbc8", }, ] } @@ -707,7 +707,7 @@ exports[`AddressInputs AddressTo should match snapshot when layout is vertical 1 @@ -853,12 +853,12 @@ exports[`AddressInputs AddressTo should match snapshot when layout is vertical 1 numberOfLines={1} style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", "fontSize": 12, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -876,7 +876,7 @@ exports[`AddressInputs AddressTo should match snapshot when layout is vertical 1 style={ [ { - "color": "#1c8234", + "color": "#1c7e33", "fontSize": 15, }, undefined, diff --git a/app/components/UI/AnimatedSpinner/__snapshots__/index.test.tsx.snap b/app/components/UI/AnimatedSpinner/__snapshots__/index.test.tsx.snap index 6c605c71682..3a80bc567d1 100644 --- a/app/components/UI/AnimatedSpinner/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/AnimatedSpinner/__snapshots__/index.test.tsx.snap @@ -4,7 +4,7 @@ exports[`AnimatedSpinner should render correctly 1`] = ` { expect(queryByTestId(APPROVAL_TAG_URL_ORIGIN_PILL)).toBeNull(); }); + + it('renders origin when only origin is provided', () => { + const { toJSON, getByTestId } = renderWithProvider( + , + { state: mockInitialState }, + ); + + expect(toJSON()).toMatchSnapshot(); + expect(getByTestId(APPROVAL_TAG_URL_ORIGIN_PILL)).toBeDefined(); + }); }); diff --git a/app/components/UI/ApprovalTagUrl/ApprovalTagUrl.tsx b/app/components/UI/ApprovalTagUrl/ApprovalTagUrl.tsx index dc7ebc8aa2d..673bb99c3c6 100644 --- a/app/components/UI/ApprovalTagUrl/ApprovalTagUrl.tsx +++ b/app/components/UI/ApprovalTagUrl/ApprovalTagUrl.tsx @@ -58,6 +58,8 @@ const ApprovalTagUrl = ({ title = prefixUrlWithProtocol(origin); } else if (url) { title = prefixUrlWithProtocol(getHost(url)); + } else if (origin) { + title = prefixUrlWithProtocol(getHost(origin)); } else { title = ''; } diff --git a/app/components/UI/ApprovalTagUrl/__snapshots__/ApprovalTagUrl.test.tsx.snap b/app/components/UI/ApprovalTagUrl/__snapshots__/ApprovalTagUrl.test.tsx.snap index e5554cae4b3..8eb0bfa805d 100644 --- a/app/components/UI/ApprovalTagUrl/__snapshots__/ApprovalTagUrl.test.tsx.snap +++ b/app/components/UI/ApprovalTagUrl/__snapshots__/ApprovalTagUrl.test.tsx.snap @@ -7,7 +7,7 @@ exports[`ApprovalTagUrl renders correctly 1`] = ` "alignItems": "center", "alignSelf": "center", "backgroundColor": "#ffffff", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 99, "borderWidth": 1, "flexDirection": "row", @@ -53,13 +53,81 @@ exports[`ApprovalTagUrl renders correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", + "color": "#686e7d", "flexShrink": 1, - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, + } + } + > + https://metamask.github.io + + +`; + +exports[`ApprovalTagUrl renders origin when only origin is provided 1`] = ` + + + + + diff --git a/app/components/UI/AssetIcon/__snapshots__/index.test.tsx.snap b/app/components/UI/AssetIcon/__snapshots__/index.test.tsx.snap index ee5feadc318..2cb976d59a2 100644 --- a/app/components/UI/AssetIcon/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/AssetIcon/__snapshots__/index.test.tsx.snap @@ -4,7 +4,7 @@ exports[`AssetIcon should render correctly 1`] = ` { const { theme } = params; @@ -10,10 +14,12 @@ const styleSheet = (params: { theme: Theme }) => { }, text: { ...typography.sBodyMD, + fontFamily: getFontFamily(TextVariant.BodyMD), marginVertical: 0, } as TextStyle, title: { ...typography.sHeadingSM, + fontFamily: getFontFamily(TextVariant.HeadingSM), marginVertical: 0, marginBottom: 4, } as TextStyle, diff --git a/app/components/UI/AssetOverview/AssetActionButton/__snapshots__/index.test.tsx.snap b/app/components/UI/AssetOverview/AssetActionButton/__snapshots__/index.test.tsx.snap index b9e1d907769..e558f6f604b 100644 --- a/app/components/UI/AssetOverview/AssetActionButton/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/AssetOverview/AssetActionButton/__snapshots__/index.test.tsx.snap @@ -20,7 +20,7 @@ exports[`AssetActionButtons should render correctly 1`] = ` { "alignContent": "center", "alignItems": "center", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 18, "height": 36, "justifyContent": "center", @@ -35,7 +35,7 @@ exports[`AssetActionButtons should render correctly 1`] = ` numberOfLines={1} style={ { - "color": "#0376c9", + "color": "#4459ff", "fontSize": 14, "marginHorizontal": 3, "marginTop": 8, @@ -67,7 +67,7 @@ exports[`AssetActionButtons should render type add correctly 1`] = ` { "alignContent": "center", "alignItems": "center", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 18, "height": 36, "justifyContent": "center", @@ -96,7 +96,7 @@ exports[`AssetActionButtons should render type add correctly 1`] = ` numberOfLines={1} style={ { - "color": "#0376c9", + "color": "#4459ff", "fontSize": 14, "marginHorizontal": 3, "marginTop": 8, @@ -128,7 +128,7 @@ exports[`AssetActionButtons should render type information correctly 1`] = ` { "alignContent": "center", "alignItems": "center", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 18, "height": 36, "justifyContent": "center", @@ -157,7 +157,7 @@ exports[`AssetActionButtons should render type information correctly 1`] = ` numberOfLines={1} style={ { - "color": "#0376c9", + "color": "#4459ff", "fontSize": 14, "marginHorizontal": 3, "marginTop": 8, @@ -189,7 +189,7 @@ exports[`AssetActionButtons should render type receive correctly 1`] = ` { "alignContent": "center", "alignItems": "center", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 18, "height": 36, "justifyContent": "center", @@ -230,7 +230,7 @@ exports[`AssetActionButtons should render type receive correctly 1`] = ` numberOfLines={1} style={ { - "color": "#0376c9", + "color": "#4459ff", "fontSize": 14, "marginHorizontal": 3, "marginTop": 8, @@ -262,7 +262,7 @@ exports[`AssetActionButtons should render type send correctly 1`] = ` { "alignContent": "center", "alignItems": "center", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 18, "height": 36, "justifyContent": "center", @@ -291,7 +291,7 @@ exports[`AssetActionButtons should render type send correctly 1`] = ` numberOfLines={1} style={ { - "color": "#0376c9", + "color": "#4459ff", "fontSize": 14, "marginHorizontal": 3, "marginTop": 8, @@ -323,7 +323,7 @@ exports[`AssetActionButtons should render type swap correctly 1`] = ` { "alignContent": "center", "alignItems": "center", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 18, "height": 36, "justifyContent": "center", @@ -358,7 +358,7 @@ exports[`AssetActionButtons should render type swap correctly 1`] = ` numberOfLines={1} style={ { - "color": "#0376c9", + "color": "#4459ff", "fontSize": 14, "marginHorizontal": 3, "marginTop": 8, diff --git a/app/components/UI/AssetOverview/AssetOverview.styles.ts b/app/components/UI/AssetOverview/AssetOverview.styles.ts index 79986f9a55c..34ba4940f1a 100644 --- a/app/components/UI/AssetOverview/AssetOverview.styles.ts +++ b/app/components/UI/AssetOverview/AssetOverview.styles.ts @@ -1,5 +1,9 @@ import type { Theme } from '@metamask/design-tokens'; import { StyleSheet, TextStyle } from 'react-native'; +import { + getFontFamily, + TextVariant, +} from '../../../component-library/components/Texts/Text'; const styleSheet = (params: { theme: Theme }) => { const { theme } = params; @@ -14,6 +18,7 @@ const styleSheet = (params: { theme: Theme }) => { }, warning: { ...typography.sBodyMD, + fontFamily: getFontFamily(TextVariant.BodyMD), borderRadius: 8, borderWidth: 1, borderColor: colors.warning.default, @@ -22,6 +27,7 @@ const styleSheet = (params: { theme: Theme }) => { } as TextStyle, warningLinks: { ...typography.sBodyMD, + fontFamily: getFontFamily(TextVariant.BodyMD), color: colors.primary.default, } as TextStyle, chartNavigationWrapper: { diff --git a/app/components/UI/AssetOverview/AssetOverview.test.tsx b/app/components/UI/AssetOverview/AssetOverview.test.tsx index 95899254886..a571d96d65c 100644 --- a/app/components/UI/AssetOverview/AssetOverview.test.tsx +++ b/app/components/UI/AssetOverview/AssetOverview.test.tsx @@ -10,14 +10,9 @@ import { MOCK_ADDRESS_2, } from '../../../util/test/accountsControllerTestUtils'; import { createBuyNavigationDetails } from '../Ramp/routes/utils'; -import { - getDecimalChainId, - isPortfolioViewEnabled, -} from '../../../util/networks'; +import { getDecimalChainId } from '../../../util/networks'; import { TokenOverviewSelectorsIDs } from '../../../../e2e/selectors/wallet/TokenOverview.selectors'; // eslint-disable-next-line import/no-namespace -import * as networks from '../../../util/networks'; -// eslint-disable-next-line import/no-namespace import * as transactions from '../../../util/transactions'; import { mockNetworkState } from '../../../util/test/network'; import Engine from '../../../core/Engine'; @@ -26,6 +21,7 @@ import { BALANCE_TEST_ID, SECONDARY_BALANCE_TEST_ID, } from '../AssetElement/index.constants'; +import { SolScope } from '@metamask/keyring-api'; const MOCK_CHAIN_ID = '0x1'; @@ -134,10 +130,9 @@ const asset = { }; describe('AssetOverview', () => { - beforeEach(() => { - jest.spyOn(networks, 'isPortfolioViewEnabled').mockReturnValue(false); + afterEach(() => { + jest.clearAllMocks(); }); - it('should render correctly', async () => { const container = renderWithProvider( { expect(container).toMatchSnapshot(); }); - it('should render correctly when portfolio view is enabled', async () => { - jest.spyOn(networks, 'isPortfolioViewEnabled').mockReturnValue(true); - - const container = renderWithProvider( - , - { state: mockInitialState }, - ); - expect(container).toMatchSnapshot(); - }); - it('should handle buy button press', async () => { const { getByTestId } = renderWithProvider( { const swapButton = getByTestId('token-swap-button'); fireEvent.press(swapButton); - if (isPortfolioViewEnabled()) { - expect(navigate).toHaveBeenCalledTimes(3); - expect(navigate).toHaveBeenNthCalledWith(1, 'RampBuy', { - screen: 'GetStarted', - params: { - address: asset.address, - chainId: getDecimalChainId(MOCK_CHAIN_ID), - }, - }); - expect(navigate).toHaveBeenNthCalledWith(2, 'SendFlowView', {}); - expect(navigate).toHaveBeenNthCalledWith(3, 'Swaps', { - screen: 'SwapsAmountView', - params: { - sourcePage: 'MainView', - address: asset.address, - chainId: MOCK_CHAIN_ID, - }, - }); - } else { - expect(navigate).toHaveBeenCalledWith('Swaps', { - screen: 'SwapsAmountView', - params: { - sourcePage: 'MainView', - sourceToken: asset.address, - chainId: '0x1', - }, - }); - } + expect(navigate).toHaveBeenCalledTimes(2); + expect(navigate).toHaveBeenNthCalledWith(1, 'WalletTabHome', { + screen: 'WalletTabStackFlow', + params: { + screen: 'WalletView', + }, + }); + expect(navigate).toHaveBeenNthCalledWith(2, 'Swaps', { + screen: 'SwapsAmountView', + params: { sourceToken: '0x123', chainId: '0x1', sourcePage: 'MainView' }, + }); + }); + + it('should handle receive button press', async () => { + const { getByTestId } = renderWithProvider( + , + { state: mockInitialState }, + ); + + const receiveButton = getByTestId('token-receive-button'); + fireEvent.press(receiveButton); + + expect(navigate).toHaveBeenCalledTimes(1); + expect(navigate).toHaveBeenNthCalledWith(1, 'QRTabSwitcher', { + disableTabber: true, + initialScreen: 1, + networkName: undefined, + }); + }); + + it('should handle bridge button press', async () => { + const { getByTestId } = renderWithProvider( + , + { state: mockInitialState }, + ); + + const receiveButton = getByTestId('token-bridge-button'); + fireEvent.press(receiveButton); + + expect(navigate).toHaveBeenCalledTimes(1); + expect(navigate).toHaveBeenNthCalledWith(1, 'BrowserTabHome', { + params: { + newTabUrl: + 'https://portfolio.metamask.io/bridge/?metamaskEntry=mobile&srcChain=1', + timestamp: 123, + }, + screen: 'BrowserView', + }); }); it('should not render swap button if displaySwapsButton is false', async () => { @@ -353,8 +362,6 @@ describe('AssetOverview', () => { }); it('should render native balances even if there are no accounts for the asset chain in the state', async () => { - jest.spyOn(networks, 'isPortfolioViewEnabled').mockReturnValue(true); - const container = renderWithProvider( { expect(container).toMatchSnapshot(); }); + it('should render native balances when non evm network is selected', async () => { + const container = renderWithProvider( + , + { + state: { + ...mockInitialState, + engine: { + ...mockInitialState.engine, + backgroundState: { + ...mockInitialState.engine.backgroundState, + MultichainNetworkController: { + selectedMultichainNetworkChainId: SolScope.Mainnet, + }, + }, + }, + }, + }, + ); + + expect(container).toMatchSnapshot(); + }); + describe('Portfolio view network switching', () => { beforeEach(() => { - jest.spyOn(networks, 'isPortfolioViewEnabled').mockReturnValue(true); jest.useFakeTimers(); // Reset mocks before each test jest.clearAllMocks(); @@ -488,8 +525,6 @@ describe('AssetOverview', () => { }); it('render mainBalance as fiat and secondaryBalance as native with portfolio view enabled', async () => { - jest.spyOn(networks, 'isPortfolioViewEnabled').mockReturnValue(true); - const { getByTestId } = renderWithProvider( , { diff --git a/app/components/UI/AssetOverview/AssetOverview.tsx b/app/components/UI/AssetOverview/AssetOverview.tsx index 88006565ef7..bd0dc8ee7bd 100644 --- a/app/components/UI/AssetOverview/AssetOverview.tsx +++ b/app/components/UI/AssetOverview/AssetOverview.tsx @@ -3,8 +3,7 @@ import { TouchableOpacity, View } from 'react-native'; import { useNavigation } from '@react-navigation/native'; import { useDispatch, useSelector } from 'react-redux'; import { Hex } from '@metamask/utils'; -import { getNativeTokenAddress } from '@metamask/assets-controllers'; -import { strings } from '../../../../locales/i18n'; +import I18n, { strings } from '../../../../locales/i18n'; import { TokenOverviewSelectorsIDs } from '../../../../e2e/selectors/wallet/TokenOverview.selectors'; import { newAssetTransaction } from '../../../actions/transaction'; import AppConstants from '../../../core/AppConstants'; @@ -13,22 +12,14 @@ import { selectEvmChainId, selectNativeCurrencyByChainId, selectSelectedNetworkClientId, - selectEvmTicker, } from '../../../selectors/networkController'; import { - selectConversionRate, selectCurrentCurrency, selectCurrencyRates, } from '../../../selectors/currencyRateController'; -import { - selectContractExchangeRates, - selectTokenMarketData, -} from '../../../selectors/tokenRatesController'; +import { selectTokenMarketData } from '../../../selectors/tokenRatesController'; import { selectAccountsByChainId } from '../../../selectors/accountTrackerController'; -import { - selectContractBalances, - selectTokensBalances, -} from '../../../selectors/tokenBalancesController'; +import { selectTokensBalances } from '../../../selectors/tokenBalancesController'; import { selectSelectedInternalAccountAddress, selectSelectedInternalAccountFormattedAddress, @@ -36,12 +27,9 @@ import { import Logger from '../../../util/Logger'; import { safeToChecksumAddress } from '../../../util/address'; import { - balanceToFiat, - hexToBN, renderFromTokenMinimalUnit, renderFromWei, toHexadecimal, - weiToFiat, } from '../../../util/number'; import { getEther } from '../../../util/transactions'; import Text from '../../Base/Text'; @@ -61,14 +49,13 @@ import { RootState } from '../../../reducers'; import useGoToBridge from '../Bridge/hooks/useGoToBridge'; import { swapsUtils } from '@metamask/swaps-controller'; import { MetaMetricsEvents } from '../../../core/Analytics'; -import { - getDecimalChainId, - isPortfolioViewEnabled, -} from '../../../util/networks'; +import { getDecimalChainId } from '../../../util/networks'; import { useMetrics } from '../../../components/hooks/useMetrics'; import { createBuyNavigationDetails } from '../Ramp/routes/utils'; import { TokenI } from '../Tokens/types'; import AssetDetailsActions from '../../../components/Views/AssetDetails/AssetDetailsActions'; +import { selectIsEvmNetworkSelected } from '../../../selectors/multichainNetworkController'; +import { formatWithThreshold } from '../../../util/assets'; interface AssetOverviewProps { asset: TokenI; @@ -90,46 +77,27 @@ const AssetOverview: React.FC = ({ const selectedInternalAccountAddress = useSelector( selectSelectedInternalAccountAddress, ); - const conversionRate = useSelector(selectConversionRate); const conversionRateByTicker = useSelector(selectCurrencyRates); const currentCurrency = useSelector(selectCurrentCurrency); const accountsByChainId = useSelector(selectAccountsByChainId); - const primaryCurrency = useSelector( - (state: RootState) => state.settings.primaryCurrency, - ); const selectedAddress = useSelector( selectSelectedInternalAccountFormattedAddress, ); const { trackEvent, createEventBuilder } = useMetrics(); - const tokenExchangeRates = useSelector(selectContractExchangeRates); const allTokenMarketData = useSelector(selectTokenMarketData); - const tokenBalances = useSelector(selectContractBalances); const selectedChainId = useSelector(selectEvmChainId); - const selectedTicker = useSelector((state: RootState) => - selectEvmTicker(state), - ); - const nativeCurrency = useSelector((state: RootState) => selectNativeCurrencyByChainId(state, asset.chainId as Hex), ); const multiChainTokenBalance = useSelector(selectTokensBalances); - const chainId = isPortfolioViewEnabled() - ? (asset.chainId as Hex) - : selectedChainId; - const ticker = isPortfolioViewEnabled() ? nativeCurrency : selectedTicker; + const chainId = asset.chainId as Hex; + const ticker = nativeCurrency; const selectedNetworkClientId = useSelector(selectSelectedNetworkClientId); + const isEvmSelected = useSelector(selectIsEvmNetworkSelected); - let currentAddress: Hex; - - if (isPortfolioViewEnabled()) { - currentAddress = asset.address as Hex; - } else { - currentAddress = asset.isETH - ? getNativeTokenAddress(chainId as Hex) - : (asset.address as Hex); - } + const currentAddress = asset.address as Hex; const { data: prices = [], isLoading } = useTokenHistoricalPrices({ address: currentAddress, @@ -198,32 +166,30 @@ const AssetOverview: React.FC = ({ : goToPortfolioBridge; const onSend = async () => { - if (isPortfolioViewEnabled()) { - navigation.navigate(Routes.WALLET.HOME, { - screen: Routes.WALLET.TAB_STACK_FLOW, - params: { - screen: Routes.WALLET_VIEW, - }, - }); + navigation.navigate(Routes.WALLET.HOME, { + screen: Routes.WALLET.TAB_STACK_FLOW, + params: { + screen: Routes.WALLET_VIEW, + }, + }); - if (asset.chainId !== selectedChainId) { - const { NetworkController, MultichainNetworkController } = - Engine.context; - const networkConfiguration = - NetworkController.getNetworkConfigurationByChainId( - asset.chainId as Hex, - ); - - const networkClientId = - networkConfiguration?.rpcEndpoints?.[ - networkConfiguration.defaultRpcEndpointIndex - ]?.networkClientId; - - await MultichainNetworkController.setActiveNetwork( - networkClientId as string, + if (asset.chainId !== selectedChainId) { + const { NetworkController, MultichainNetworkController } = Engine.context; + const networkConfiguration = + NetworkController.getNetworkConfigurationByChainId( + asset.chainId as Hex, ); - } + + const networkClientId = + networkConfiguration?.rpcEndpoints?.[ + networkConfiguration.defaultRpcEndpointIndex + ]?.networkClientId; + + await MultichainNetworkController.setActiveNetwork( + networkClientId as string, + ); } + if ((asset.isETH || asset.isNative) && ticker) { dispatch(newAssetTransaction(getEther(ticker))); } else { @@ -233,57 +199,33 @@ const AssetOverview: React.FC = ({ }; const goToSwaps = useCallback(() => { - if (isPortfolioViewEnabled()) { - navigation.navigate(Routes.WALLET.HOME, { - screen: Routes.WALLET.TAB_STACK_FLOW, - params: { - screen: Routes.WALLET_VIEW, - }, - }); - if (asset.chainId !== selectedChainId) { - const { NetworkController, MultichainNetworkController } = - Engine.context; - const networkConfiguration = - NetworkController.getNetworkConfigurationByChainId( - asset.chainId as Hex, - ); - - const networkClientId = - networkConfiguration?.rpcEndpoints?.[ - networkConfiguration.defaultRpcEndpointIndex - ]?.networkClientId; - - MultichainNetworkController.setActiveNetwork( - networkClientId as string, - ).then(() => { - setTimeout(() => { - handleSwapNavigation(); - }, 500); - }); - } else { + navigation.navigate(Routes.WALLET.HOME, { + screen: Routes.WALLET.TAB_STACK_FLOW, + params: { + screen: Routes.WALLET_VIEW, + }, + }); + if (asset.chainId !== selectedChainId) { + const { NetworkController, MultichainNetworkController } = Engine.context; + const networkConfiguration = + NetworkController.getNetworkConfigurationByChainId( + asset.chainId as Hex, + ); + + const networkClientId = + networkConfiguration?.rpcEndpoints?.[ + networkConfiguration.defaultRpcEndpointIndex + ]?.networkClientId; + + MultichainNetworkController.setActiveNetwork( + networkClientId as string, + ).then(() => { handleSwapNavigation(); - } + }); } else { handleSwapNavigation(); - trackEvent( - createEventBuilder(MetaMetricsEvents.SWAP_BUTTON_CLICKED) - .addProperties({ - text: 'Swap', - tokenSymbol: '', - location: 'TokenDetails', - chain_id: getDecimalChainId(asset.chainId), - }) - .build(), - ); } - }, [ - navigation, - asset.chainId, - selectedChainId, - trackEvent, - createEventBuilder, - handleSwapNavigation, - ]); + }, [navigation, asset.chainId, selectedChainId, handleSwapNavigation]); const onBuy = () => { navigation.navigate( @@ -349,31 +291,28 @@ const AssetOverview: React.FC = ({ ); const itemAddress = safeToChecksumAddress(asset.address); - let exchangeRate: number | undefined; - if (!isPortfolioViewEnabled()) { - exchangeRate = itemAddress - ? tokenExchangeRates?.[itemAddress as Hex]?.price - : undefined; - } else { - const currentChainId = chainId as Hex; - exchangeRate = - allTokenMarketData?.[currentChainId]?.[itemAddress as Hex]?.price; - } + const currentChainId = chainId as Hex; + const exchangeRate = + allTokenMarketData?.[currentChainId]?.[itemAddress as Hex]?.price; + + let balance; + const minimumDisplayThreshold = 0.00001; - let balance, balanceFiat; - if (asset.isETH || asset.isNative) { + const isMultichainAsset = !isEvmSelected; + const isEthOrNative = asset.isETH || asset.isNative; + + if (isMultichainAsset) { + balance = formatWithThreshold( + parseFloat(asset.balance), + minimumDisplayThreshold, + I18n.locale, + { minimumFractionDigits: 0, maximumFractionDigits: 5 }, + ); + } else if (isEthOrNative) { balance = renderFromWei( - //@ts-expect-error - This should be fixed at the accountsController selector level, ongoing discussion + // @ts-expect-error - This should be fixed at the accountsController selector level, ongoing discussion accountsByChainId[toHexadecimal(chainId)]?.[selectedAddress]?.balance, ); - balanceFiat = weiToFiat( - hexToBN( - //@ts-expect-error - This should be fixed at the accountsController selector level, ongoing discussion - accountsByChainId[toHexadecimal(chainId)]?.[selectedAddress]?.balance, - ), - conversionRate, - currentCurrency, - ); } else { const multiChainTokenBalanceHex = itemAddress && @@ -381,58 +320,28 @@ const AssetOverview: React.FC = ({ chainId as Hex ]?.[itemAddress as Hex]; - const selectedTokenBalanceHex = - itemAddress && tokenBalances?.[itemAddress as Hex]; - - const tokenBalanceHex = isPortfolioViewEnabled() - ? multiChainTokenBalanceHex - : selectedTokenBalanceHex; + const tokenBalanceHex = multiChainTokenBalanceHex; balance = itemAddress && tokenBalanceHex ? renderFromTokenMinimalUnit(tokenBalanceHex, asset.decimals) : 0; - balanceFiat = balanceToFiat( - balance, - conversionRate, - exchangeRate, - currentCurrency, - ); } - let mainBalance, secondaryBalance; - if (!isPortfolioViewEnabled()) { - if (primaryCurrency === 'ETH') { - mainBalance = `${balance} ${asset.symbol}`; - secondaryBalance = balanceFiat; - } else { - mainBalance = !balanceFiat ? `${balance} ${asset.symbol}` : balanceFiat; - secondaryBalance = !balanceFiat - ? balanceFiat - : `${balance} ${asset.symbol}`; - } - } else { - mainBalance = asset.balanceFiat || ''; - secondaryBalance = `${balance} ${asset.isETH ? asset.ticker : asset.symbol}`; - } + const mainBalance = asset.balanceFiat || ''; + const secondaryBalance = `${balance} ${ + asset.isETH ? asset.ticker : asset.symbol + }`; let currentPrice = 0; let priceDiff = 0; - if (!isPortfolioViewEnabled()) { - if (asset.isETH) { - currentPrice = conversionRate || 0; - } else if (exchangeRate && conversionRate) { - currentPrice = exchangeRate * conversionRate; - } - } else { - const tickerConversionRate = - conversionRateByTicker?.[nativeCurrency]?.conversionRate ?? 0; - currentPrice = - exchangeRate && tickerConversionRate - ? exchangeRate * tickerConversionRate - : 0; - } + const tickerConversionRate = + conversionRateByTicker?.[nativeCurrency]?.conversionRate ?? 0; + currentPrice = + exchangeRate && tickerConversionRate + ? exchangeRate * tickerConversionRate + : 0; const comparePrice = prices[0]?.[1] || 0; if (currentPrice !== undefined && currentPrice !== null) { diff --git a/app/components/UI/AssetOverview/Balance/Balance.styles.tsx b/app/components/UI/AssetOverview/Balance/Balance.styles.tsx index 335718d5c39..04aef9fde37 100644 --- a/app/components/UI/AssetOverview/Balance/Balance.styles.tsx +++ b/app/components/UI/AssetOverview/Balance/Balance.styles.tsx @@ -1,5 +1,9 @@ import type { Theme } from '@metamask/design-tokens'; import { StyleSheet, TextStyle } from 'react-native'; +import { + getFontFamily, + TextVariant, +} from '../../../../component-library/components/Texts/Text'; const styleSheet = (params: { theme: Theme }) => { const { theme } = params; @@ -29,10 +33,12 @@ const styleSheet = (params: { theme: Theme }) => { } as TextStyle, text: { ...typography.sBodySM, + fontFamily: getFontFamily(TextVariant.BodySM), marginVertical: 0, } as TextStyle, fiatBalance: { ...typography.sHeadingMD, + fontFamily: getFontFamily(TextVariant.HeadingMD), } as TextStyle, }); }; diff --git a/app/components/UI/AssetOverview/Balance/Balance.tsx b/app/components/UI/AssetOverview/Balance/Balance.tsx index 081e3b4180a..0f09c7c594b 100644 --- a/app/components/UI/AssetOverview/Balance/Balance.tsx +++ b/app/components/UI/AssetOverview/Balance/Balance.tsx @@ -1,30 +1,22 @@ import React, { useCallback } from 'react'; import { View } from 'react-native'; -import { Hex } from '@metamask/utils'; +import { Hex, isCaipChainId } from '@metamask/utils'; import { strings } from '../../../../../locales/i18n'; import { useStyles } from '../../../../component-library/hooks'; import styleSheet from './Balance.styles'; import AssetElement from '../../AssetElement'; import { useSelector } from 'react-redux'; -import { - selectChainId, - selectNetworkConfigurationByChainId, -} from '../../../../selectors/networkController'; +import { selectNetworkConfigurationByChainId } from '../../../../selectors/networkController'; import { getTestNetImageByChainId, getDefaultNetworkByChainId, - isLineaMainnetByChainId, - isMainnetByChainId, isTestNet, - isPortfolioViewEnabled, } from '../../../../util/networks'; -import images from '../../../../images/image-icons'; import BadgeWrapper, { BadgePosition, } from '../../../../component-library/components/Badges/BadgeWrapper'; import { BadgeVariant } from '../../../../component-library/components/Badges/Badge/Badge.types'; import Badge from '../../../../component-library/components/Badges/Badge/Badge'; -import NetworkMainAssetLogo from '../../NetworkMainAssetLogo'; import AvatarToken from '../../../../component-library/components/Avatars/Avatar/variants/AvatarToken'; import { AvatarSize } from '../../../../component-library/components/Avatars/Avatar'; import NetworkAssetLogo from '../../NetworkAssetLogo'; @@ -38,6 +30,7 @@ import { PopularList, UnpopularNetworkList, CustomNetworkImgMapping, + getNonEvmNetworkImageSourceByChainId, } from '../../../../util/networks/customNetworks'; import { RootState } from '../../../../reducers'; @@ -47,22 +40,7 @@ interface BalanceProps { secondaryBalance?: string; } -export const NetworkBadgeSource = (chainId: Hex, ticker: string) => { - const isMainnet = isMainnetByChainId(chainId); - const isLineaMainnet = isLineaMainnetByChainId(chainId); - if (!isPortfolioViewEnabled()) { - if (isTestNet(chainId)) return getTestNetImageByChainId(chainId); - if (isMainnet) return images.ETHEREUM; - - if (isLineaMainnet) return images['LINEA-MAINNET']; - - if (CustomNetworkImgMapping[chainId]) { - return CustomNetworkImgMapping[chainId]; - } - - return ticker ? images[ticker as keyof typeof images] : undefined; - } - +export const NetworkBadgeSource = (chainId: Hex) => { if (isTestNet(chainId)) return getTestNetImageByChainId(chainId); const defaultNetwork = getDefaultNetworkByChainId(chainId) as | { @@ -88,6 +66,11 @@ export const NetworkBadgeSource = (chainId: Hex, ticker: string) => { if (network) { return network.rpcPrefs.imageSource; } + + if (isCaipChainId(chainId)) { + return getNonEvmNetworkImageSourceByChainId(chainId); + } + if (customNetworkImg) { return customNetworkImg; } @@ -99,18 +82,11 @@ const Balance = ({ asset, mainBalance, secondaryBalance }: BalanceProps) => { const networkConfigurationByChainId = useSelector((state: RootState) => selectNetworkConfigurationByChainId(state, asset.chainId as Hex), ); - const chainId = useSelector(selectChainId); - const tokenChainId = isPortfolioViewEnabled() ? asset.chainId : chainId; - - const ticker = asset.symbol; + const tokenChainId = asset.chainId; const renderNetworkAvatar = useCallback(() => { - if (!isPortfolioViewEnabled() && asset.isETH) { - return ; - } - - if (isPortfolioViewEnabled() && asset.isNative) { + if (asset.isNative) { return ( { /> ); }, [ - asset.isETH, asset.image, asset.symbol, asset.isNative, @@ -163,7 +138,7 @@ const Balance = ({ asset, mainBalance, secondaryBalance }: BalanceProps) => { badgeElement={ } diff --git a/app/components/UI/AssetOverview/Balance/__snapshots__/index.test.tsx.snap b/app/components/UI/AssetOverview/Balance/__snapshots__/index.test.tsx.snap index 243e4f69c79..1db4954479a 100644 --- a/app/components/UI/AssetOverview/Balance/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/AssetOverview/Balance/__snapshots__/index.test.tsx.snap @@ -12,8 +12,8 @@ exports[`Balance should render correctly with main and secondary balance 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", + "color": "#121314", + "fontFamily": "CentraNo1-Bold", "fontSize": 18, "fontWeight": "700", "letterSpacing": 0, @@ -127,7 +127,7 @@ exports[`Balance should render correctly with main and secondary balance 1`] = ` "height": 32, "justifyContent": "center", "overflow": "hidden", - "shadowColor": "#0000001A", + "shadowColor": "#0000001a", "shadowOffset": { "height": 2, "width": 0, @@ -164,10 +164,10 @@ exports[`Balance should render correctly with main and secondary balance 1`] = ` style={ { "alignSelf": "center", - "color": "#141618", + "color": "#121314", "flex": 1, - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "justifyContent": "center", "letterSpacing": 0, @@ -191,9 +191,9 @@ exports[`Balance should render correctly with main and secondary balance 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "letterSpacing": 0, "lineHeight": 24, @@ -207,12 +207,12 @@ exports[`Balance should render correctly with main and secondary balance 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, "paddingHorizontal": 0, "textTransform": "uppercase", } @@ -238,8 +238,8 @@ exports[`Balance should render correctly without a secondary balance 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", + "color": "#121314", + "fontFamily": "CentraNo1-Bold", "fontSize": 18, "fontWeight": "700", "letterSpacing": 0, @@ -353,7 +353,7 @@ exports[`Balance should render correctly without a secondary balance 1`] = ` "height": 32, "justifyContent": "center", "overflow": "hidden", - "shadowColor": "#0000001A", + "shadowColor": "#0000001a", "shadowOffset": { "height": 2, "width": 0, @@ -390,10 +390,10 @@ exports[`Balance should render correctly without a secondary balance 1`] = ` style={ { "alignSelf": "center", - "color": "#141618", + "color": "#121314", "flex": 1, - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "justifyContent": "center", "letterSpacing": 0, @@ -417,9 +417,9 @@ exports[`Balance should render correctly without a secondary balance 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "letterSpacing": 0, "lineHeight": 24, diff --git a/app/components/UI/AssetOverview/Balance/index.test.tsx b/app/components/UI/AssetOverview/Balance/index.test.tsx index c112891f998..4db83cc9a41 100644 --- a/app/components/UI/AssetOverview/Balance/index.test.tsx +++ b/app/components/UI/AssetOverview/Balance/index.test.tsx @@ -8,7 +8,6 @@ import { Provider, useSelector } from 'react-redux'; import configureMockStore from 'redux-mock-store'; import { backgroundState } from '../../../../util/test/initial-root-state'; import { NetworkBadgeSource } from './Balance'; -import { isPortfolioViewEnabled } from '../../../../util/networks'; import { MOCK_VAULT_APY_AVERAGES } from '../../Stake/components/PoolStakingLearnMoreModal/mockVaultRewards'; jest.mock('react-redux', () => ({ @@ -82,7 +81,6 @@ jest.mock('../../../../util/networks', () => ({ jest.mock('../../../../util/networks', () => ({ ...jest.requireActual('../../../../util/networks'), - isPortfolioViewEnabled: jest.fn(), })); jest.mock('../../Stake/hooks/usePooledStakes', () => ({ @@ -148,27 +146,23 @@ describe('Balance', () => { jest.clearAllMocks(); }); - if (!isPortfolioViewEnabled()) { - it('should render correctly with main and secondary balance', () => { - const wrapper = render( - , - ); - expect(wrapper).toMatchSnapshot(); - }); - } + it('should render correctly with main and secondary balance', () => { + const wrapper = render( + , + ); + expect(wrapper).toMatchSnapshot(); + }); - if (!isPortfolioViewEnabled()) { - it('should render correctly without a secondary balance', () => { - const wrapper = render( - , - ); - expect(wrapper).toMatchSnapshot(); - }); - } + it('should render correctly without a secondary balance', () => { + const wrapper = render( + , + ); + expect(wrapper).toMatchSnapshot(); + }); it('should fire navigation event for non native tokens', () => { const { queryByTestId } = render( @@ -198,59 +192,45 @@ describe('Balance', () => { describe('NetworkBadgeSource', () => { it('returns testnet image for a testnet chainId', () => { - const result = NetworkBadgeSource('0xaa36a7', 'ETH'); + const result = NetworkBadgeSource('0xaa36a7'); expect(result).toBeDefined(); }); it('returns mainnet Ethereum image for mainnet chainId', () => { - const result = NetworkBadgeSource('0x1', 'ETH'); + const result = NetworkBadgeSource('0x1'); expect(result).toBeDefined(); }); it('returns Linea Mainnet image for Linea mainnet chainId', () => { - const result = NetworkBadgeSource('0xe708', 'LINEA'); + const result = NetworkBadgeSource('0xe708'); expect(result).toBeDefined(); }); it('returns undefined if no image is found', () => { - const result = NetworkBadgeSource('0x999', 'UNKNOWN'); + const result = NetworkBadgeSource('0x999'); expect(result).toBeUndefined(); }); - - it('returns Linea Mainnet image for Linea mainnet chainId isPortfolioViewEnabled is true', () => { - if (isPortfolioViewEnabled()) { - const result = NetworkBadgeSource('0xe708', 'LINEA'); - expect(result).toBeDefined(); - } - }); }); }); describe('NetworkBadgeSource', () => { it('returns testnet image for a testnet chainId', () => { - const result = NetworkBadgeSource('0xaa36a7', 'ETH'); + const result = NetworkBadgeSource('0xaa36a7'); expect(result).toBeDefined(); }); it('returns mainnet Ethereum image for mainnet chainId', () => { - const result = NetworkBadgeSource('0x1', 'ETH'); - expect(result).toBeDefined(); - }); - - it('returns Linea Mainnet image for Linea mainnet chainId', () => { - const result = NetworkBadgeSource('0xe708', 'LINEA'); + const result = NetworkBadgeSource('0x1'); expect(result).toBeDefined(); }); it('returns undefined if no image is found', () => { - const result = NetworkBadgeSource('0x999', 'UNKNOWN'); + const result = NetworkBadgeSource('0x999'); expect(result).toBeUndefined(); }); - it('returns Linea Mainnet image for Linea mainnet chainId isPortfolioViewEnabled is true', () => { - if (isPortfolioViewEnabled()) { - const result = NetworkBadgeSource('0xe708', 'LINEA'); - expect(result).toBeDefined(); - } + it('returns Linea Mainnet image for Linea mainnet chainId', () => { + const result = NetworkBadgeSource('0xe708'); + expect(result).toBeDefined(); }); }); diff --git a/app/components/UI/AssetOverview/PriceChart/PriceChart.styles.tsx b/app/components/UI/AssetOverview/PriceChart/PriceChart.styles.tsx index d027fbcc803..0a104de03d5 100644 --- a/app/components/UI/AssetOverview/PriceChart/PriceChart.styles.tsx +++ b/app/components/UI/AssetOverview/PriceChart/PriceChart.styles.tsx @@ -1,5 +1,9 @@ import type { Theme } from '@metamask/design-tokens'; import { Dimensions, StyleSheet, TextStyle } from 'react-native'; +import { + getFontFamily, + TextVariant, +} from '../../../../component-library/components/Texts/Text'; export const CHART_HEIGHT = Dimensions.get('screen').height * 0.44; @@ -32,6 +36,7 @@ const styleSheet = (params: { theme: Theme }) => { }, noDataOverlayTitle: { ...typography.sHeadingMD, + fontFamily: getFontFamily(TextVariant.HeadingMD), textAlign: 'center', } as TextStyle, noDataOverlayText: { diff --git a/app/components/UI/AssetOverview/TokenDetails/MarketDetailsList/__snapshots__/MarketDetailsList.test.tsx.snap b/app/components/UI/AssetOverview/TokenDetails/MarketDetailsList/__snapshots__/MarketDetailsList.test.tsx.snap index aeb4ec4ca5b..6b50f52a9ba 100644 --- a/app/components/UI/AssetOverview/TokenDetails/MarketDetailsList/__snapshots__/MarketDetailsList.test.tsx.snap +++ b/app/components/UI/AssetOverview/TokenDetails/MarketDetailsList/__snapshots__/MarketDetailsList.test.tsx.snap @@ -6,8 +6,8 @@ exports[`MarketDetailsList should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", + "color": "#121314", + "fontFamily": "CentraNo1-Bold", "fontSize": 18, "fontWeight": "700", "letterSpacing": 0, @@ -44,12 +44,12 @@ exports[`MarketDetailsList should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -59,12 +59,12 @@ exports[`MarketDetailsList should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > @@ -84,12 +84,12 @@ exports[`MarketDetailsList should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -99,12 +99,12 @@ exports[`MarketDetailsList should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > @@ -124,12 +124,12 @@ exports[`MarketDetailsList should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -139,12 +139,12 @@ exports[`MarketDetailsList should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > @@ -164,12 +164,12 @@ exports[`MarketDetailsList should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -179,12 +179,12 @@ exports[`MarketDetailsList should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > @@ -204,12 +204,12 @@ exports[`MarketDetailsList should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -219,12 +219,12 @@ exports[`MarketDetailsList should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > @@ -244,12 +244,12 @@ exports[`MarketDetailsList should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -259,12 +259,12 @@ exports[`MarketDetailsList should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > @@ -284,12 +284,12 @@ exports[`MarketDetailsList should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -299,12 +299,12 @@ exports[`MarketDetailsList should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > diff --git a/app/components/UI/AssetOverview/TokenDetails/TokenDetails.test.tsx b/app/components/UI/AssetOverview/TokenDetails/TokenDetails.test.tsx index 01338fa8480..cf97270a233 100644 --- a/app/components/UI/AssetOverview/TokenDetails/TokenDetails.test.tsx +++ b/app/components/UI/AssetOverview/TokenDetails/TokenDetails.test.tsx @@ -20,7 +20,7 @@ import * as reactRedux from 'react-redux'; import * as StakeConstants from '../../Stake/constants'; import { strings } from '../../../../../locales/i18n'; jest.mock('../../../../core/Engine', () => ({ - getTotalFiatAccountBalance: jest.fn(), + getTotalEvmFiatAccountBalance: jest.fn(), context: { TokensController: {}, }, diff --git a/app/components/UI/AssetOverview/TokenDetails/TokenDetailsList/__snapshots__/TokenDetailsList.test.tsx.snap b/app/components/UI/AssetOverview/TokenDetails/TokenDetailsList/__snapshots__/TokenDetailsList.test.tsx.snap index fdc7d0280fa..30a2977fb79 100644 --- a/app/components/UI/AssetOverview/TokenDetails/TokenDetailsList/__snapshots__/TokenDetailsList.test.tsx.snap +++ b/app/components/UI/AssetOverview/TokenDetails/TokenDetailsList/__snapshots__/TokenDetailsList.test.tsx.snap @@ -6,8 +6,8 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", + "color": "#121314", + "fontFamily": "CentraNo1-Bold", "fontSize": 18, "fontWeight": "700", "letterSpacing": 0, @@ -44,12 +44,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -60,7 +60,7 @@ exports[`TokenDetails should render correctly 1`] = ` style={ { "alignItems": "center", - "backgroundColor": "#0376C91A", + "backgroundColor": "#4459ff1a", "borderRadius": 20, "flexDirection": "row", "marginLeft": 8, @@ -72,19 +72,19 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#0376c9", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#4459ff", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > 0x6B17...1d0F @@ -126,12 +126,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > @@ -156,12 +156,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -171,12 +171,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > diff --git a/app/components/UI/AssetOverview/TokenDetails/__snapshots__/TokenDetails.test.tsx.snap b/app/components/UI/AssetOverview/TokenDetails/__snapshots__/TokenDetails.test.tsx.snap index d95cf04e77f..6be1e07d082 100644 --- a/app/components/UI/AssetOverview/TokenDetails/__snapshots__/TokenDetails.test.tsx.snap +++ b/app/components/UI/AssetOverview/TokenDetails/__snapshots__/TokenDetails.test.tsx.snap @@ -14,8 +14,8 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", + "color": "#121314", + "fontFamily": "CentraNo1-Bold", "fontSize": 18, "fontWeight": "700", "letterSpacing": 0, @@ -52,12 +52,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -68,7 +68,7 @@ exports[`TokenDetails should render correctly 1`] = ` style={ { "alignItems": "center", - "backgroundColor": "#0376C91A", + "backgroundColor": "#4459ff1a", "borderRadius": 20, "flexDirection": "row", "marginLeft": 8, @@ -80,19 +80,19 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#0376c9", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#4459ff", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > 0x6B17...1d0F @@ -134,12 +134,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > @@ -164,12 +164,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -179,12 +179,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > @@ -198,8 +198,8 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", + "color": "#121314", + "fontFamily": "CentraNo1-Bold", "fontSize": 18, "fontWeight": "700", "letterSpacing": 0, @@ -236,12 +236,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -251,12 +251,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > @@ -276,12 +276,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -291,12 +291,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > @@ -316,12 +316,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -331,12 +331,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > @@ -356,12 +356,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -371,12 +371,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > @@ -396,12 +396,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -411,12 +411,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > @@ -436,12 +436,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -451,12 +451,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > @@ -476,12 +476,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -491,12 +491,12 @@ exports[`TokenDetails should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 20, + "lineHeight": 22, } } > diff --git a/app/components/UI/AssetOverview/__snapshots__/AssetOverview.test.tsx.snap b/app/components/UI/AssetOverview/__snapshots__/AssetOverview.test.tsx.snap index 53a3ff73ee5..470dc8ecd13 100644 --- a/app/components/UI/AssetOverview/__snapshots__/AssetOverview.test.tsx.snap +++ b/app/components/UI/AssetOverview/__snapshots__/AssetOverview.test.tsx.snap @@ -21,12 +21,12 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -39,8 +39,8 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", + "color": "#121314", + "fontFamily": "CentraNo1-Bold", "fontSize": 24, "fontWeight": "700", "letterSpacing": 0, @@ -89,12 +89,12 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -189,7 +189,7 @@ exports[`AssetOverview should render correctly 1`] = ` style={ { "alignItems": "center", - "backgroundColor": "#00000014", + "backgroundColor": "#858b9a29", "borderRadius": 40, "justifyContent": "center", "paddingHorizontal": 8, @@ -202,12 +202,12 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 3, - "lineHeight": 20, + "lineHeight": 22, "textAlign": "center", } } @@ -233,12 +233,12 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 3, - "lineHeight": 20, + "lineHeight": 22, "textAlign": "center", } } @@ -264,12 +264,12 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 3, - "lineHeight": 20, + "lineHeight": 22, "textAlign": "center", } } @@ -295,12 +295,12 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 3, - "lineHeight": 20, + "lineHeight": 22, "textAlign": "center", } } @@ -326,12 +326,12 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 3, - "lineHeight": 20, + "lineHeight": 22, "textAlign": "center", } } @@ -357,12 +357,12 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 3, - "lineHeight": 20, + "lineHeight": 22, "textAlign": "center", } } @@ -419,7 +419,7 @@ exports[`AssetOverview should render correctly 1`] = ` style={ { "alignItems": "center", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 20, "height": 40, "justifyContent": "center", @@ -447,9 +447,9 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "letterSpacing": 0, "lineHeight": 24, @@ -460,12 +460,12 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } /> @@ -475,12 +475,12 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -525,7 +525,7 @@ exports[`AssetOverview should render correctly 1`] = ` style={ { "alignItems": "center", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 20, "height": 40, "justifyContent": "center", @@ -553,9 +553,9 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "letterSpacing": 0, "lineHeight": 24, @@ -566,12 +566,12 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } /> @@ -581,12 +581,12 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -631,7 +631,7 @@ exports[`AssetOverview should render correctly 1`] = ` style={ { "alignItems": "center", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 20, "height": 40, "justifyContent": "center", @@ -659,9 +659,9 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "letterSpacing": 0, "lineHeight": 24, @@ -672,12 +672,12 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } /> @@ -687,12 +687,12 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -737,7 +737,7 @@ exports[`AssetOverview should render correctly 1`] = ` style={ { "alignItems": "center", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 20, "height": 40, "justifyContent": "center", @@ -765,9 +765,9 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "letterSpacing": 0, "lineHeight": 24, @@ -778,12 +778,12 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } /> @@ -793,12 +793,12 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -843,7 +843,7 @@ exports[`AssetOverview should render correctly 1`] = ` style={ { "alignItems": "center", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 20, "height": 40, "justifyContent": "center", @@ -871,9 +871,9 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "letterSpacing": 0, "lineHeight": 24, @@ -884,12 +884,12 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } /> @@ -899,12 +899,12 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -923,8 +923,8 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", + "color": "#121314", + "fontFamily": "CentraNo1-Bold", "fontSize": 18, "fontWeight": "700", "letterSpacing": 0, @@ -1038,7 +1038,7 @@ exports[`AssetOverview should render correctly 1`] = ` "height": 32, "justifyContent": "center", "overflow": "hidden", - "shadowColor": "#0000001A", + "shadowColor": "#0000001a", "shadowOffset": { "height": 2, "width": 0, @@ -1075,10 +1075,10 @@ exports[`AssetOverview should render correctly 1`] = ` style={ { "alignSelf": "center", - "color": "#141618", + "color": "#121314", "flex": 1, - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "justifyContent": "center", "letterSpacing": 0, @@ -1102,15 +1102,33 @@ exports[`AssetOverview should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "letterSpacing": 0, "lineHeight": 24, } } testID="balance-test-id" + > + 1500 + + 0 ETH @@ -1129,7 +1147,7 @@ exports[`AssetOverview should render correctly 1`] = ` `; -exports[`AssetOverview should render correctly when portfolio view is enabled 1`] = ` +exports[`AssetOverview should render native balances even if there are no accounts for the asset chain in the state 1`] = ` @@ -1168,8 +1186,8 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", + "color": "#121314", + "fontFamily": "CentraNo1-Bold", "fontSize": 24, "fontWeight": "700", "letterSpacing": 0, @@ -1218,12 +1236,12 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -1318,7 +1336,7 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` style={ { "alignItems": "center", - "backgroundColor": "#00000014", + "backgroundColor": "#858b9a29", "borderRadius": 40, "justifyContent": "center", "paddingHorizontal": 8, @@ -1331,12 +1349,12 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 3, - "lineHeight": 20, + "lineHeight": 22, "textAlign": "center", } } @@ -1362,12 +1380,12 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 3, - "lineHeight": 20, + "lineHeight": 22, "textAlign": "center", } } @@ -1393,12 +1411,12 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 3, - "lineHeight": 20, + "lineHeight": 22, "textAlign": "center", } } @@ -1424,12 +1442,12 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 3, - "lineHeight": 20, + "lineHeight": 22, "textAlign": "center", } } @@ -1455,12 +1473,12 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 3, - "lineHeight": 20, + "lineHeight": 22, "textAlign": "center", } } @@ -1486,12 +1504,12 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 3, - "lineHeight": 20, + "lineHeight": 22, "textAlign": "center", } } @@ -1548,7 +1566,7 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` style={ { "alignItems": "center", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 20, "height": 40, "justifyContent": "center", @@ -1576,9 +1594,9 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "letterSpacing": 0, "lineHeight": 24, @@ -1589,12 +1607,12 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } /> @@ -1604,12 +1622,12 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -1654,7 +1672,7 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` style={ { "alignItems": "center", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 20, "height": 40, "justifyContent": "center", @@ -1682,9 +1700,9 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "letterSpacing": 0, "lineHeight": 24, @@ -1695,12 +1713,12 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } /> @@ -1710,12 +1728,12 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -1760,7 +1778,7 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` style={ { "alignItems": "center", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 20, "height": 40, "justifyContent": "center", @@ -1788,9 +1806,9 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "letterSpacing": 0, "lineHeight": 24, @@ -1801,12 +1819,12 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } /> @@ -1816,12 +1834,12 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -1866,7 +1884,7 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` style={ { "alignItems": "center", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 20, "height": 40, "justifyContent": "center", @@ -1894,9 +1912,9 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "letterSpacing": 0, "lineHeight": 24, @@ -1907,12 +1925,12 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } /> @@ -1922,12 +1940,12 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -1972,7 +1990,7 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` style={ { "alignItems": "center", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 20, "height": 40, "justifyContent": "center", @@ -2000,9 +2018,9 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "letterSpacing": 0, "lineHeight": 24, @@ -2013,12 +2031,12 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } /> @@ -2028,12 +2046,12 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -2052,8 +2070,8 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", + "color": "#121314", + "fontFamily": "CentraNo1-Bold", "fontSize": 18, "fontWeight": "700", "letterSpacing": 0, @@ -2091,33 +2109,67 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` > + + > + + - + > + ? + @@ -2204,10 +2259,10 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` style={ { "alignSelf": "center", - "color": "#141618", + "color": "#121314", "flex": 1, - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "justifyContent": "center", "letterSpacing": 0, @@ -2231,9 +2286,9 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "letterSpacing": 0, "lineHeight": 24, @@ -2247,12 +2302,12 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, "paddingHorizontal": 0, "textTransform": "uppercase", } @@ -2276,7 +2331,7 @@ exports[`AssetOverview should render correctly when portfolio view is enabled 1` `; -exports[`AssetOverview should render native balances even if there are no accounts for the asset chain in the state 1`] = ` +exports[`AssetOverview should render native balances when non evm network is selected 1`] = ` @@ -2315,8 +2370,8 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", + "color": "#121314", + "fontFamily": "CentraNo1-Bold", "fontSize": 24, "fontWeight": "700", "letterSpacing": 0, @@ -2365,12 +2420,12 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -2465,7 +2520,7 @@ exports[`AssetOverview should render native balances even if there are no accoun style={ { "alignItems": "center", - "backgroundColor": "#00000014", + "backgroundColor": "#858b9a29", "borderRadius": 40, "justifyContent": "center", "paddingHorizontal": 8, @@ -2478,12 +2533,12 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 3, - "lineHeight": 20, + "lineHeight": 22, "textAlign": "center", } } @@ -2509,12 +2564,12 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 3, - "lineHeight": 20, + "lineHeight": 22, "textAlign": "center", } } @@ -2540,12 +2595,12 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 3, - "lineHeight": 20, + "lineHeight": 22, "textAlign": "center", } } @@ -2571,12 +2626,12 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 3, - "lineHeight": 20, + "lineHeight": 22, "textAlign": "center", } } @@ -2602,12 +2657,12 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 3, - "lineHeight": 20, + "lineHeight": 22, "textAlign": "center", } } @@ -2633,12 +2688,12 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 12, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 14, "fontWeight": "400", "letterSpacing": 3, - "lineHeight": 20, + "lineHeight": 22, "textAlign": "center", } } @@ -2695,7 +2750,7 @@ exports[`AssetOverview should render native balances even if there are no accoun style={ { "alignItems": "center", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 20, "height": 40, "justifyContent": "center", @@ -2723,9 +2778,9 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "letterSpacing": 0, "lineHeight": 24, @@ -2736,12 +2791,12 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } /> @@ -2751,12 +2806,12 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -2801,7 +2856,7 @@ exports[`AssetOverview should render native balances even if there are no accoun style={ { "alignItems": "center", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 20, "height": 40, "justifyContent": "center", @@ -2829,9 +2884,9 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "letterSpacing": 0, "lineHeight": 24, @@ -2842,12 +2897,12 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } /> @@ -2857,12 +2912,12 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -2907,7 +2962,7 @@ exports[`AssetOverview should render native balances even if there are no accoun style={ { "alignItems": "center", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 20, "height": 40, "justifyContent": "center", @@ -2935,9 +2990,9 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "letterSpacing": 0, "lineHeight": 24, @@ -2948,12 +3003,12 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } /> @@ -2963,12 +3018,12 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -3013,7 +3068,7 @@ exports[`AssetOverview should render native balances even if there are no accoun style={ { "alignItems": "center", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 20, "height": 40, "justifyContent": "center", @@ -3041,9 +3096,9 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "letterSpacing": 0, "lineHeight": 24, @@ -3054,12 +3109,12 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } /> @@ -3069,12 +3124,12 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -3119,7 +3174,7 @@ exports[`AssetOverview should render native balances even if there are no accoun style={ { "alignItems": "center", - "backgroundColor": "#0376c9", + "backgroundColor": "#4459ff", "borderRadius": 20, "height": 40, "justifyContent": "center", @@ -3147,9 +3202,9 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "letterSpacing": 0, "lineHeight": 24, @@ -3160,12 +3215,12 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } /> @@ -3175,12 +3230,12 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -3199,8 +3254,8 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", + "color": "#121314", + "fontFamily": "CentraNo1-Bold", "fontSize": 18, "fontWeight": "700", "letterSpacing": 0, @@ -3341,14 +3396,14 @@ exports[`AssetOverview should render native balances even if there are no accoun style={ { "alignItems": "center", - "backgroundColor": "#f2f4f6", + "backgroundColor": "#ffffff", "borderColor": "#ffffff", - "borderRadius": 16, + "borderRadius": 8, "borderWidth": 2, "height": 32, "justifyContent": "center", "overflow": "hidden", - "shadowColor": "#0000001A", + "shadowColor": "#0000001a", "shadowOffset": { "height": 2, "width": 0, @@ -3364,21 +3419,18 @@ exports[`AssetOverview should render native balances even if there are no accoun } } > - - ? - + testID="network-avatar-image" + /> @@ -3388,10 +3440,10 @@ exports[`AssetOverview should render native balances even if there are no accoun style={ { "alignSelf": "center", - "color": "#141618", + "color": "#121314", "flex": 1, - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "justifyContent": "center", "letterSpacing": 0, @@ -3415,9 +3467,9 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 16, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 18, "fontWeight": "500", "letterSpacing": 0, "lineHeight": 24, @@ -3431,19 +3483,19 @@ exports[`AssetOverview should render native balances even if there are no accoun accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, "paddingHorizontal": 0, "textTransform": "uppercase", } } testID="secondary-balance-test-id" > - 0 ETH + 400 ETH diff --git a/app/components/UI/AssetSearch/__snapshots__/index.test.tsx.snap b/app/components/UI/AssetSearch/__snapshots__/index.test.tsx.snap index 81d026d360c..3476e4516f3 100644 --- a/app/components/UI/AssetSearch/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/AssetSearch/__snapshots__/index.test.tsx.snap @@ -6,10 +6,10 @@ exports[`AssetSearch should render correctly 1`] = ` [ { "alignItems": "center", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 8, "borderWidth": 1, - "color": "#141618", + "color": "#121314", "flex": 1, "flexDirection": "row", "justifyContent": "center", @@ -23,13 +23,13 @@ exports[`AssetSearch should render correctly 1`] = ` @@ -250,7 +250,7 @@ exports[`BasicFunctionalityModal should render correctly 1`] = ` "alignItems": "center", "alignSelf": "flex-start", "backgroundColor": "transparent", - "borderColor": "#0376c9", + "borderColor": "#4459ff", "borderRadius": 24, "borderWidth": 1, "flex": 1, @@ -265,12 +265,12 @@ exports[`BasicFunctionalityModal should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#0376c9", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#4459ff", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -296,7 +296,7 @@ exports[`BasicFunctionalityModal should render correctly 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#d73847", + "backgroundColor": "#ca3542", "borderRadius": 24, "flex": 1, "flexDirection": "row", @@ -312,11 +312,11 @@ exports[`BasicFunctionalityModal should render correctly 1`] = ` style={ { "color": "#ffffff", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > diff --git a/app/components/UI/BasicFunctionality/__snapshots__/BasicFunctionality.test.js.snap b/app/components/UI/BasicFunctionality/__snapshots__/BasicFunctionality.test.js.snap index b5e83cf60b3..727778ace74 100644 --- a/app/components/UI/BasicFunctionality/__snapshots__/BasicFunctionality.test.js.snap +++ b/app/components/UI/BasicFunctionality/__snapshots__/BasicFunctionality.test.js.snap @@ -22,8 +22,8 @@ exports[`BasicFunctionality should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Bold", + "color": "#121314", + "fontFamily": "CentraNo1-Bold", "fontSize": 16, "fontWeight": "700", "letterSpacing": 0, @@ -38,7 +38,7 @@ exports[`BasicFunctionality should render correctly 1`] = ` onChange={[Function]} onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} - onTintColor="#0376c9" + onTintColor="#4459ff" style={ [ { @@ -46,13 +46,13 @@ exports[`BasicFunctionality should render correctly 1`] = ` "width": 51, }, { - "backgroundColor": "#BBC0C566", + "backgroundColor": "#b7bbc866", "borderRadius": 16, }, ] } thumbTintColor="#ffffff" - tintColor="#BBC0C566" + tintColor="#b7bbc866" value={true} /> @@ -60,12 +60,12 @@ exports[`BasicFunctionality should render correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#6a737d", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#686e7d", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -75,12 +75,12 @@ exports[`BasicFunctionality should render correctly 1`] = ` onPress={[Function]} style={ { - "color": "#0376c9", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 14, + "color": "#4459ff", + "fontFamily": "CentraNo1-Book", + "fontSize": 16, "fontWeight": "400", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > diff --git a/app/components/UI/BiometryButton/BiometryButton.tsx b/app/components/UI/BiometryButton/BiometryButton.tsx index 6a279b28eb6..b2fec5f1f23 100644 --- a/app/components/UI/BiometryButton/BiometryButton.tsx +++ b/app/components/UI/BiometryButton/BiometryButton.tsx @@ -6,6 +6,7 @@ import { useTheme } from '../../../util/theme'; import { BIOMETRY_TYPE } from 'react-native-keychain'; import AUTHENTICATION_TYPE from '../../../constants/userProperties'; import { createStyles } from './styles'; +import { LoginViewSelectors } from '../../../../e2e/selectors/wallet/LoginView.selectors'; /* eslint-disable @typescript-eslint/no-require-imports */ /* eslint-disable @typescript-eslint/no-var-requires */ @@ -14,12 +15,12 @@ const iosFaceId = require('../../../images/ios-face-id.png'); const androidFaceRecognition = require('../../../images/android-face-recognition.png'); const androidIris = require('../../../images/android-iris.png'); -type BiometryType = BIOMETRY_TYPE | AUTHENTICATION_TYPE; +type BiometryType = BIOMETRY_TYPE | AUTHENTICATION_TYPE | string | null; interface BiometryButtonProps { onPress: () => void; hidden: boolean; - biometryType: BiometryType; + biometryType: BiometryType | null; } const BiometryButton = ({ @@ -32,49 +33,71 @@ const BiometryButton = ({ const renderIcon = (type: BiometryType) => { if (Platform.OS === 'ios') { - if (type === 'TouchID') { + if (type === BIOMETRY_TYPE.TOUCH_ID) { return ( ); - } else if (type.includes(AUTHENTICATION_TYPE.PASSCODE)) { + } else if (type?.includes(AUTHENTICATION_TYPE.PASSCODE)) { return ( ); } - return ; + return ( + + ); } if (Platform.OS === 'android') { - if (type === 'Fingerprint') { + if (type === BIOMETRY_TYPE.FINGERPRINT) { return ( ); - } else if (type === 'Face') { - return ; - } else if (type === 'Iris') { - return ; - } else if (type.includes(AUTHENTICATION_TYPE.PASSCODE)) { + } else if (type === BIOMETRY_TYPE.FACE) { + return ( + + ); + } else if (type === BIOMETRY_TYPE.IRIS) { + return ( + + ); + } else if (type?.includes(AUTHENTICATION_TYPE.PASSCODE)) { return ( ); } @@ -86,6 +109,7 @@ const BiometryButton = ({ style={styles.fixCenterIcon} size={28} name="ios-finger-print" + testID={LoginViewSelectors.FALLBACK_FINGERPRINT_ICON} /> ); }; @@ -93,8 +117,12 @@ const BiometryButton = ({ if (hidden) return null; return ( - - {renderIcon(biometryType)} + + {biometryType ? renderIcon(biometryType) : null} ); }; diff --git a/app/components/UI/BiometryButton/__snapshots__/index.test.tsx.snap b/app/components/UI/BiometryButton/__snapshots__/index.test.tsx.snap deleted file mode 100644 index 155f8d93441..00000000000 --- a/app/components/UI/BiometryButton/__snapshots__/index.test.tsx.snap +++ /dev/null @@ -1,26 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`BiometryButton should render correctly 1`] = ` - - - -`; diff --git a/app/components/UI/BiometryButton/index.test.tsx b/app/components/UI/BiometryButton/index.test.tsx index ee582854358..d24c495213b 100644 --- a/app/components/UI/BiometryButton/index.test.tsx +++ b/app/components/UI/BiometryButton/index.test.tsx @@ -1,18 +1,152 @@ import React from 'react'; import { render } from '@testing-library/react-native'; +import { Platform } from 'react-native'; +import { BIOMETRY_TYPE } from 'react-native-keychain'; import BiometryButton from './BiometryButton'; import AUTHENTICATION_TYPE from '../../../constants/userProperties'; +import { LoginViewSelectors } from '../../../../e2e/selectors/wallet/LoginView.selectors'; + +jest.mock('react-native', () => ({ + ...jest.requireActual('react-native'), + Platform: { OS: 'ios' }, +})); + +const mockOnPress = jest.fn(); describe('BiometryButton', () => { - it('should render correctly', () => { + it('should hide when hidden is true', () => { const { toJSON } = render( {}} + onPress={mockOnPress} + hidden + biometryType={BIOMETRY_TYPE.FACE} + />, + ); + + expect(toJSON()).toBeNull(); + }); + + describe('ios', () => { + beforeEach(() => { + Platform.OS = 'ios'; + }); + + it('should render touch id icon', () => { + const { getByTestId } = render( + @@ -1161,15 +1138,11 @@ exports[`BridgeSourceTokenSelector renders with initial state and displays token style={null} > - - - + + - - - - + > + + - - - - ETH - - - Ethereum - - - - + FOO + + - $40000 - - + Foo Token + + + - 20 ETH - + + $80000 + + + 5 FOO + + @@ -1443,15 +1398,11 @@ exports[`BridgeSourceTokenSelector renders with initial state and displays token style={null} > - - - - - + + + + + + + + - + > + + + + + ETH + + + Ethereum + + + + + $40000 + + + 20 ETH + + + + + + + + - - TOKEN1 - - + + + + + - Token One - - - - + + + + + + + + - $20000 - - + TOKEN1 + + + Token One + + + - 1 TOKEN1 - + + $20000 + + + 1 TOKEN1 + + @@ -1694,18 +1950,14 @@ exports[`BridgeSourceTokenSelector renders with initial state and displays token style={null} > - - - + + - + + + - - - + > + + - - - - ETH - - - Ethereum - - - - + ETH + + - $6000 - - + Ethereum + + + - 3 ETH - + + $6000 + + + 3 ETH + + diff --git a/app/components/UI/Bridge/components/BridgeSourceTokenSelector/index.tsx b/app/components/UI/Bridge/components/BridgeSourceTokenSelector/index.tsx index d3f5e7f354c..114b53742f6 100644 --- a/app/components/UI/Bridge/components/BridgeSourceTokenSelector/index.tsx +++ b/app/components/UI/Bridge/components/BridgeSourceTokenSelector/index.tsx @@ -1,49 +1,74 @@ import React, { useCallback, useMemo } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { useNavigation } from '@react-navigation/native'; -import { TokenI } from '../../../Tokens/types'; import { Hex } from '@metamask/utils'; -import { selectNetworkConfigurations } from '../../../../../selectors/networkController'; -import { selectSelectedSourceChainIds, selectEnabledSourceChains, setSourceToken, selectSourceToken } from '../../../../../core/redux/slices/bridge'; +import { selectEvmNetworkConfigurationsByChainId, selectNetworkConfigurations } from '../../../../../selectors/networkController'; +import { selectSelectedSourceChainIds, selectEnabledSourceChains, setSourceToken, selectSourceToken, selectDestToken } from '../../../../../core/redux/slices/bridge'; import { getNetworkImageSource } from '../../../../../util/networks'; import { TokenSelectorItem } from '../TokenSelectorItem'; -import { TokenIWithFiatAmount } from '../../hooks/useTokensWithBalance'; import { useSortedSourceNetworks } from '../../hooks/useSortedSourceNetworks'; import { BridgeSourceNetworksBar, MAX_NETWORK_ICONS } from '../BridgeSourceNetworksBar'; import { BridgeTokenSelectorBase } from '../BridgeTokenSelectorBase'; -import { useSourceTokens } from '../../hooks/useSourceTokens'; +import { useTokens } from '../../hooks/useTokens'; +import { BridgeToken } from '../../types'; +import { useSwitchNetworks } from '../../../../Views/NetworkSelector/useSwitchNetworks'; +import { useNetworkInfo } from '../../../../../selectors/selectedNetworkController'; export const BridgeSourceTokenSelector: React.FC = () => { const dispatch = useDispatch(); const navigation = useNavigation(); - const networkConfigurations = useSelector(selectNetworkConfigurations); + const evmNetworkConfigurations = useSelector(selectEvmNetworkConfigurationsByChainId); + const allNetworkConfigurations = useSelector(selectNetworkConfigurations); const enabledSourceChains = useSelector(selectEnabledSourceChains); const selectedSourceChainIds = useSelector(selectSelectedSourceChainIds); - const tokensList = useSourceTokens(); const { sortedSourceNetworks } = useSortedSourceNetworks(); const selectedSourceToken = useSelector(selectSourceToken); + const selectedDestToken = useSelector(selectDestToken); + const { + chainId: selectedChainId, + domainIsConnectedDapp, + networkName: selectedNetworkName, + } = useNetworkInfo(); + const { onSetRpcTarget } = useSwitchNetworks({ + domainIsConnectedDapp, + selectedChainId, + selectedNetworkName, + }); - const renderItem = useCallback(({ item }: { item: TokenIWithFiatAmount }) => { - const handleTokenPress = (token: TokenI) => { + const { tokens: tokensList, pending } = useTokens({ + topTokensChainId: selectedSourceToken?.chainId as Hex, + balanceChainIds: selectedSourceChainIds as Hex[], + tokensToExclude: selectedDestToken ? [selectedDestToken] : [], + }); + + const renderItem = useCallback(({ item }: { item: BridgeToken }) => { + const handleTokenPress = async (token: BridgeToken) => { dispatch(setSourceToken(token)); + + // Switch to the chain of the selected token + const networkConfiguration = evmNetworkConfigurations[token.chainId]; + if (networkConfiguration) { + await onSetRpcTarget(networkConfiguration); + } + navigation.goBack(); }; return ( - ); - }, [dispatch, navigation, networkConfigurations, selectedSourceToken]); + }, [dispatch, navigation, evmNetworkConfigurations, allNetworkConfigurations, selectedSourceToken, onSetRpcTarget]); const networksToShow = useMemo(() => sortedSourceNetworks @@ -57,13 +82,14 @@ export const BridgeSourceTokenSelector: React.FC = () => { networksBar={ } renderTokenItem={renderItem} tokensList={tokensList} + pending={pending} /> ); }; diff --git a/app/components/UI/Bridge/components/BridgeTokenSelectorBase.tsx b/app/components/UI/Bridge/components/BridgeTokenSelectorBase.tsx index f2430273b62..4e6079c732e 100644 --- a/app/components/UI/Bridge/components/BridgeTokenSelectorBase.tsx +++ b/app/components/UI/Bridge/components/BridgeTokenSelectorBase.tsx @@ -1,19 +1,26 @@ import React, { useCallback, useMemo, useRef } from 'react'; import { StyleSheet, FlatList, TouchableOpacity } from 'react-native'; import { Box } from '../../Box/Box'; -import Text, { TextVariant, TextColor } from '../../../../component-library/components/Texts/Text'; +import Text, { + TextVariant, + TextColor, +} from '../../../../component-library/components/Texts/Text'; import { useStyles } from '../../../../component-library/hooks'; import { Theme } from '../../../../util/theme/models'; import BottomSheetHeader from '../../../../component-library/components/BottomSheets/BottomSheetHeader'; -import BottomSheet, { BottomSheetRef } from '../../../../component-library/components/BottomSheets/BottomSheet'; -import { TokenI } from '../../Tokens/types'; -import Icon, { IconName } from '../../../../component-library/components/Icons/Icon'; +import BottomSheet, { + BottomSheetRef, +} from '../../../../component-library/components/BottomSheets/BottomSheet'; +import Icon, { + IconName, +} from '../../../../component-library/components/Icons/Icon'; import { IconSize } from '../../../../component-library/components/Icons/Icon/Icon.types'; -import { TokenIWithFiatAmount } from '../hooks/useTokensWithBalance'; import { strings } from '../../../../../locales/i18n'; import { FlexDirection, AlignItems, JustifyContent } from '../../Box/box.types'; import { useTokenSearch } from '../hooks/useTokenSearch'; import TextFieldSearch from '../../../../component-library/components/Form/TextFieldSearch'; +import { BridgeToken } from '../types'; +import { Skeleton } from '../../../../component-library/components/Skeleton'; const createStyles = (params: { theme: Theme }) => { const { theme } = params; @@ -44,34 +51,89 @@ const createStyles = (params: { theme: Theme }) => { paddingHorizontal: 16, paddingVertical: 12, }, + loadingSkeleton: { + padding: 16, + }, + skeletonCircle: { + borderRadius: 15, + }, + // Need the flex 1 to make sure this doesn't disappear when FlexDirection.Row is used + skeletonItem: { + flex: 1, + } }); }; +const SkeletonItem = () => { + const { styles } = useStyles(createStyles, {}); + + return ( + + + + + + + + + + + ); +}; + +const LoadingSkeleton = () => { + const { styles } = useStyles(createStyles, {}); + + return ( + + + + + + + + + + + + + ); +}; + interface BridgeTokenSelectorBaseProps { networksBar: React.ReactNode; - renderTokenItem: ({ item }: { item: TokenIWithFiatAmount }) => React.JSX.Element; - tokensList: TokenIWithFiatAmount[]; + renderTokenItem: ({ item }: { item: BridgeToken }) => React.JSX.Element; + tokensList: BridgeToken[]; + pending?: boolean; } -export const BridgeTokenSelectorBase: React.FC = ({ - networksBar, - renderTokenItem, - tokensList, -}) => { +export const BridgeTokenSelectorBase: React.FC< + BridgeTokenSelectorBaseProps +> = ({ networksBar, renderTokenItem, tokensList, pending }) => { const { styles, theme } = useStyles(createStyles, {}); const { searchString, setSearchString, searchResults } = useTokenSearch({ tokens: tokensList || [], }); - const tokensToRender = useMemo(() => - searchString ? searchResults : tokensList, - [searchString, searchResults, tokensList] + const tokensToRender = useMemo( + () => (searchString ? searchResults : tokensList), + [searchString, searchResults, tokensList], ); - const keyExtractor = useCallback((token: TokenI) => `${token.chainId}-${token.address}`, []); + const keyExtractor = useCallback( + (token: BridgeToken) => `${token.chainId}-${token.address}`, + [], + ); - const handleSearchTextChange = useCallback((text: string) => { - setSearchString(text); - }, [setSearchString]); + const handleSearchTextChange = useCallback( + (text: string) => { + setSearchString(text); + }, + [setSearchString], + ); const renderEmptyList = useMemo( () => ( @@ -90,10 +152,7 @@ export const BridgeTokenSelectorBase: React.FC = ( }; return ( - + @@ -129,14 +188,14 @@ export const BridgeTokenSelectorBase: React.FC = ( onChangeText={handleSearchTextChange} placeholder={strings('swaps.search_token')} testID="bridge-token-search-input" - /> + /> diff --git a/app/components/UI/Bridge/components/QuoteDetailsCard/QuoteDetailsCard.styles.ts b/app/components/UI/Bridge/components/QuoteDetailsCard/QuoteDetailsCard.styles.ts new file mode 100644 index 00000000000..7eac89d92f0 --- /dev/null +++ b/app/components/UI/Bridge/components/QuoteDetailsCard/QuoteDetailsCard.styles.ts @@ -0,0 +1,30 @@ +import { StyleSheet } from 'react-native'; +import { Theme } from '../../../../../util/theme/models'; + +const createStyles = ({ colors }: Theme) => + StyleSheet.create({ + container: { + backgroundColor: colors.background.default, + borderWidth: 1, + borderRadius: 8, + borderColor: colors.border.muted, + overflow: 'hidden', + paddingVertical: 12, + paddingHorizontal: 16, + gap: 12, + }, + gradientContainer: { + position: 'absolute', + bottom: 0, + left: 0, + right: 0, + height: 30, + }, + networkContainer: { + flexDirection: 'row', + flexWrap: 'wrap', + maxWidth: '80%', + }, + }); + +export default createStyles; diff --git a/app/components/UI/Bridge/components/QuoteDetailsCard/QuoteDetailsCard.test.tsx b/app/components/UI/Bridge/components/QuoteDetailsCard/QuoteDetailsCard.test.tsx new file mode 100644 index 00000000000..1507d070d58 --- /dev/null +++ b/app/components/UI/Bridge/components/QuoteDetailsCard/QuoteDetailsCard.test.tsx @@ -0,0 +1,224 @@ +import { fireEvent } from '@testing-library/react-native'; +import { + renderScreen, + DeepPartial, +} from '../../../../../util/test/renderWithProvider'; +import QuoteDetailsCard from './QuoteDetailsCard'; +import { strings } from '../../../../../../locales/i18n'; +import Routes from '../../../../../constants/navigation/Routes'; +import { defaultBridgeControllerState } from '../../../../../core/Engine/controllers/bridge-controller/constants'; +import mockQuotes from '../../_mocks_/mock-quotes-native-erc20.json'; +import { QuoteResponse } from '@metamask/bridge-controller'; +import { mockNetworkState } from '../../../../../util/test/network'; +import { RpcEndpointType } from '@metamask/network-controller'; +import { mockBridgeReducerState } from '../../_mocks_/bridgeReducerState'; +import initialRootState from '../../../../../util/test/initial-root-state'; +import { RootState } from '../../../../../reducers'; +import { ChainId } from '@metamask/controller-utils'; +import { createMockInternalAccount } from '../../../../../util/test/accountsControllerTestUtils'; + +const mockNavigate = jest.fn(); +jest.mock('@react-navigation/native', () => ({ + ...jest.requireActual('@react-navigation/native'), + useNavigation: () => ({ + navigate: mockNavigate, + }), +})); + +describe('QuoteDetailsCard', () => { + const mockAccount = createMockInternalAccount( + '0x1234567890123456789012345678901234567890', + 'Test Account', + ); + + const initialState: DeepPartial = { + engine: { + backgroundState: { + ...initialRootState, + BridgeController: { + ...defaultBridgeControllerState, + quotes: mockQuotes as unknown as QuoteResponse[], + }, + NetworkController: { + ...mockNetworkState( + { + chainId: ChainId.mainnet, + id: 'mainnet', + nickname: 'Ethereum', + ticker: 'ETH', + type: RpcEndpointType.Infura, + rpcUrl: 'https://eth-mainnet.alchemyapi.io/v2/demo', + }, + { + chainId: ChainId['linea-mainnet'], + id: 'linea', + nickname: 'Linea', + ticker: 'LINEA', + type: RpcEndpointType.Custom, + rpcUrl: 'https://linea-rpc.com', + }, + ), + }, + MultichainNetworkController: { + multichainNetworkConfigurationsByChainId: {}, + }, + AccountsController: { + internalAccounts: { + accounts: { + [mockAccount.id]: mockAccount, + }, + selectedAccount: mockAccount.id, + }, + }, + }, + }, + bridge: mockBridgeReducerState, + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('renders initial state', () => { + const { toJSON } = renderScreen( + QuoteDetailsCard, + { + name: Routes.BRIDGE.ROOT, + }, + { state: initialState }, + ); + expect(toJSON()).toMatchSnapshot(); + }); + + it('renders expanded state', () => { + const { getByLabelText, toJSON } = renderScreen( + QuoteDetailsCard, + { + name: Routes.BRIDGE.ROOT, + }, + { state: initialState }, + ); + + // Expand the accordion + const expandButton = getByLabelText('Expand quote details'); + fireEvent.press(expandButton); + + expect(toJSON()).toMatchSnapshot(); + }); + + it('displays fee amount', () => { + const { getByText } = renderScreen( + QuoteDetailsCard, + { + name: Routes.BRIDGE.ROOT, + }, + { state: initialState }, + ); + + expect(getByText('$0.01')).toBeDefined(); + }); + + it('displays processing time', () => { + const { getByText } = renderScreen( + QuoteDetailsCard, + { + name: Routes.BRIDGE.ROOT, + }, + { state: initialState }, + ); + + expect(getByText('1 min')).toBeDefined(); + }); + + it('displays quote rate', () => { + const { getByText } = renderScreen( + QuoteDetailsCard, + { + name: Routes.BRIDGE.ROOT, + }, + { state: initialState }, + ); + + expect(getByText('1 ETH = 0.0 USDC')).toBeDefined(); + }); + + it('toggles content visibility on chevron press', () => { + const { getByLabelText, queryByText } = renderScreen( + QuoteDetailsCard, + { + name: Routes.BRIDGE.ROOT, + }, + { state: initialState }, + ); + + // Initially price impact should not be visible + expect(queryByText(strings('bridge.price_impact'))).toBeNull(); + + // Press chevron to expand + const expandButton = getByLabelText('Expand quote details'); + fireEvent.press(expandButton); + + // After expansion, price impact should be visible + expect(queryByText(strings('bridge.price_impact'))).toBeDefined(); + expect(queryByText('-0.06%')).toBeDefined(); + + // Press chevron again to collapse + fireEvent.press(expandButton); + + // After collapse, price impact should not be visible + expect(queryByText(strings('bridge.price_impact'))).toBeNull(); + }); + + it('navigates to slippage modal on edit press', () => { + const { getByLabelText, getByTestId } = renderScreen( + QuoteDetailsCard, + { + name: Routes.BRIDGE.ROOT, + }, + { state: initialState }, + ); + + // Expand the accordion first + const expandButton = getByLabelText('Expand quote details'); + fireEvent.press(expandButton); + + // Find and press the edit button + const editButton = getByTestId('edit-slippage-button'); + fireEvent.press(editButton); + + // Check if navigation was called with correct params + expect(mockNavigate).toHaveBeenCalledWith(Routes.BRIDGE.MODALS.ROOT, { + screen: Routes.BRIDGE.MODALS.SLIPPAGE_MODAL, + }); + }); + + it('displays network names', () => { + const { getByText } = renderScreen( + QuoteDetailsCard, + { + name: Routes.BRIDGE.ROOT, + }, + { state: initialState }, + ); + + expect(getByText('Ethereum')).toBeDefined(); + expect(getByText('Linea')).toBeDefined(); + }); + + it('displays slippage value', () => { + const { getByLabelText, getByText } = renderScreen( + QuoteDetailsCard, + { + name: Routes.BRIDGE.ROOT, + }, + { state: initialState }, + ); + + // Expand the accordion first + const expandButton = getByLabelText('Expand quote details'); + fireEvent.press(expandButton); + + // Verify slippage value + expect(getByText('0.5%')).toBeDefined(); + }); +}); diff --git a/app/components/UI/Bridge/components/QuoteDetailsCard/QuoteDetailsCard.tsx b/app/components/UI/Bridge/components/QuoteDetailsCard/QuoteDetailsCard.tsx new file mode 100644 index 00000000000..ed3ce62442a --- /dev/null +++ b/app/components/UI/Bridge/components/QuoteDetailsCard/QuoteDetailsCard.tsx @@ -0,0 +1,334 @@ +import React, { useState, useCallback } from 'react'; +import { + TouchableOpacity, + LayoutAnimation, + Platform, + UIManager, +} from 'react-native'; +import { useNavigation } from '@react-navigation/native'; +import { strings } from '../../../../../../locales/i18n'; +import Text, { + TextVariant, +} from '../../../../../component-library/components/Texts/Text'; +import { useTheme } from '../../../../../util/theme'; +import createStyles from './QuoteDetailsCard.styles'; +import Icon, { + IconColor, + IconName, + IconSize, +} from '../../../../../component-library/components/Icons/Icon'; +import KeyValueRow from '../../../../../component-library/components-temp/KeyValueRow'; +import { TooltipSizes } from '../../../../../component-library/components-temp/KeyValueRow/KeyValueRow.types'; +import Animated, { + interpolate, + useAnimatedStyle, + useSharedValue, + withTiming, +} from 'react-native-reanimated'; +import Svg, { Defs, LinearGradient, Rect, Stop } from 'react-native-svg'; +import { Box } from '../../../Box/Box'; +import { + FlexDirection, + AlignItems, + JustifyContent, +} from '../../../Box/box.types'; +import Routes from '../../../../../constants/navigation/Routes'; +import { BadgeVariant } from '../../../../../component-library/components/Badges/Badge/Badge.types'; +import Badge from '../../../../../component-library/components/Badges/Badge'; +import { getNetworkImageSource } from '../../../../../util/networks'; +import { AvatarSize } from '../../../../../component-library/components/Avatars/Avatar/Avatar.types'; +import mockQuotes from '../../_mocks_/mock-quotes-native-erc20.json'; +import { QuoteResponse } from '@metamask/bridge-controller'; +import { useSelector } from 'react-redux'; +import { + selectDestToken, + selectSlippage, + selectSourceToken, +} from '../../../../../core/redux/slices/bridge'; +import { selectNetworkConfigurations } from '../../../../../selectors/networkController'; + +// Enable Layout Animation on Android +if (Platform.OS === 'android') { + if (UIManager.setLayoutAnimationEnabledExperimental) { + UIManager.setLayoutAnimationEnabledExperimental(true); + } +} + +const ANIMATION_DURATION_MS = 300; + +interface NetworkBadgeProps { + chainId: string; +} + +const NetworkBadge = ({ chainId }: NetworkBadgeProps) => { + const networkConfigurations = useSelector(selectNetworkConfigurations); + const networkConfig = networkConfigurations[chainId]; + const displayName = networkConfig?.name || ''; + + return ( + + + {displayName} + + ); +}; + +// Using first quote from mock data +const quoteDetails = mockQuotes[0] as unknown as QuoteResponse; //TODO: Remove this once we have a real quote from the controller MMS-1886 + +const QuoteDetailsCard = () => { + const theme = useTheme(); + const navigation = useNavigation(); + const styles = createStyles(theme); + const [isExpanded, setIsExpanded] = useState(false); + const rotationValue = useSharedValue(0); + + const slippage = useSelector(selectSlippage); + const sourceToken = useSelector(selectSourceToken); + const destToken = useSelector(selectDestToken); + + const toggleAccordion = useCallback(() => { + LayoutAnimation.configureNext( + LayoutAnimation.create( + ANIMATION_DURATION_MS, + LayoutAnimation.Types.easeInEaseOut, + LayoutAnimation.Properties.opacity, + ), + ); + + const newExpandedState = !isExpanded; + setIsExpanded(newExpandedState); + rotationValue.value = withTiming(newExpandedState ? 1 : 0, { + duration: ANIMATION_DURATION_MS, + }); + }, [isExpanded, rotationValue]); + + const arrowStyle = useAnimatedStyle(() => { + const rotation = interpolate(rotationValue.value, [0, 1], [0, 180]); + return { + transform: [{ rotate: `${rotation}deg` }], + }; + }); + + const handleQuoteInfoPress = () => { + navigation.navigate(Routes.BRIDGE.MODALS.ROOT, { + screen: Routes.BRIDGE.MODALS.QUOTE_INFO_MODAL, + }); + }; + + const handleSlippagePress = () => { + navigation.navigate(Routes.BRIDGE.MODALS.ROOT, { + screen: Routes.BRIDGE.MODALS.SLIPPAGE_MODAL, + }); + }; + + if (!quoteDetails || !sourceToken?.chainId || !destToken?.chainId) { + return null; + } + + const isSameChainId = sourceToken.chainId === destToken.chainId; + + const { quote, estimatedProcessingTimeInSeconds } = quoteDetails; + + // Format the data for display + const quoteData = { + networkFee: '$0.01', // TODO: Calculate from quote.feeData + estimatedTime: `${Math.ceil(estimatedProcessingTimeInSeconds / 60)} min`, + rate: `1 ${sourceToken.symbol} = ${( + Number(quote.destTokenAmount) / Number(quote.srcTokenAmount) + ).toFixed(1)} ${destToken.symbol}`, + priceImpact: '-0.06%', // TODO: Calculate from quote data + slippage: `${slippage}%`, // TODO: Get from bridge settings + srcChainId: sourceToken.chainId, + destChainId: destToken.chainId, + }; + + return ( + + + {!isSameChainId ? ( + + + + + + ) : ( + + <> + + )} + + + + + + + + + + {/* Always visible content */} + + + + + {/* Quote info with gradient overlay */} + + + {!isExpanded && ( + + + + + + + + + + + + )} + + + {/* Expandable content */} + {isExpanded && ( + + + + + + {strings('bridge.slippage') || 'Slippage'} + + + + + + ), + }} + value={{ + label: { + text: quoteData.slippage, + variant: TextVariant.BodyMD, + }, + }} + /> + + )} + + ); +}; + +export default QuoteDetailsCard; diff --git a/app/components/UI/Bridge/components/QuoteDetailsCard/QuoteDetailsCard.types.ts b/app/components/UI/Bridge/components/QuoteDetailsCard/QuoteDetailsCard.types.ts new file mode 100644 index 00000000000..0cfc7c96e95 --- /dev/null +++ b/app/components/UI/Bridge/components/QuoteDetailsCard/QuoteDetailsCard.types.ts @@ -0,0 +1,43 @@ +export interface QuoteDetailsCardProps { + /** + * Source network name + */ + sourceNetwork: { + name: string; + iconUrl?: string; + }; + /** + * Destination network name + */ + destNetwork: { + name: string; + iconUrl?: string; + }; + /** + * Network fee in USD + */ + networkFee: string; + /** + * Estimated time for the transaction + */ + estimatedTime: string; + /** + * Quote details + */ + quote: { + rate: string; + priceImpact: string; + }; + /** + * Current slippage setting + */ + slippage: string; + /** + * Callback when slippage is pressed + */ + onSlippagePress: () => void; + /** + * ID for testing purposes + */ + testID?: string; +} diff --git a/app/components/UI/Bridge/components/QuoteDetailsCard/__snapshots__/QuoteDetailsCard.test.tsx.snap b/app/components/UI/Bridge/components/QuoteDetailsCard/__snapshots__/QuoteDetailsCard.test.tsx.snap new file mode 100644 index 00000000000..b6a69cd19a7 --- /dev/null +++ b/app/components/UI/Bridge/components/QuoteDetailsCard/__snapshots__/QuoteDetailsCard.test.tsx.snap @@ -0,0 +1,2169 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`QuoteDetailsCard renders expanded state 1`] = ` + + + + + + + + + + + + + Bridge + + + + + + + + + + + + + + + + + + + + + + + + + + + Ethereum + + + + + + + + + + + Linea + + + + + + + + + + + + + + + + + Network Fee + + + + + + + + + $0.01 + + + + + + + + + + + Time + + + + + + + + + 1 min + + + + + + + + + + + + Quote + + + + + + + + + + + + 1 ETH = 0.0 USDC + + + + + + + + + + + + + Price Impact + + + + + + + + + -0.06% + + + + + + + + + + + + Slippage + + + + + + + + + + + + + 0.5% + + + + + + + + + + + + + + + + + +`; + +exports[`QuoteDetailsCard renders initial state 1`] = ` + + + + + + + + + + + + + Bridge + + + + + + + + + + + + + + + + + + + + + + + + + + + Ethereum + + + + + + + + + + + Linea + + + + + + + + + + + + + + + + + Network Fee + + + + + + + + + $0.01 + + + + + + + + + + + Time + + + + + + + + + 1 min + + + + + + + + + + + + Quote + + + + + + + + + + + + 1 ETH = 0.0 USDC + + + + + + + + + + + + + + + + + + + + + + + + + + + +`; diff --git a/app/components/UI/Bridge/components/QuoteDetailsCard/index.ts b/app/components/UI/Bridge/components/QuoteDetailsCard/index.ts new file mode 100644 index 00000000000..56d259449fc --- /dev/null +++ b/app/components/UI/Bridge/components/QuoteDetailsCard/index.ts @@ -0,0 +1 @@ +export { default } from './QuoteDetailsCard'; diff --git a/app/components/UI/Bridge/components/QuoteInfoModal/__snapshots__/QuoteInfoModal.test.tsx.snap b/app/components/UI/Bridge/components/QuoteInfoModal/__snapshots__/QuoteInfoModal.test.tsx.snap index f0dc872cc55..a0081c0ca14 100644 --- a/app/components/UI/Bridge/components/QuoteInfoModal/__snapshots__/QuoteInfoModal.test.tsx.snap +++ b/app/components/UI/Bridge/components/QuoteInfoModal/__snapshots__/QuoteInfoModal.test.tsx.snap @@ -34,7 +34,7 @@ exports[`QuoteInfoModal renders correctly 1`] = ` style={ [ { - "backgroundColor": "#00000099", + "backgroundColor": "#00000066", "bottom": 0, "left": 0, "position": "absolute", @@ -81,14 +81,14 @@ exports[`QuoteInfoModal renders correctly 1`] = ` [ { "backgroundColor": "#ffffff", - "borderColor": "#BBC0C566", + "borderColor": "#b7bbc866", "borderTopLeftRadius": 8, "borderTopRightRadius": 8, "borderWidth": 1, "maxHeight": 1334, "overflow": "hidden", "paddingBottom": 0, - "shadowColor": "#0000001A", + "shadowColor": "#0000001a", "shadowOffset": { "height": 2, "width": 0, @@ -118,7 +118,7 @@ exports[`QuoteInfoModal renders correctly 1`] = ` @@ -266,7 +266,7 @@ exports[`QuoteInfoModal renders correctly 1`] = ` "alignItems": "center", "alignSelf": "flex-start", "backgroundColor": "transparent", - "borderColor": "#0376c9", + "borderColor": "#4459ff", "borderRadius": 24, "borderWidth": 1, "flex": 1, @@ -282,12 +282,12 @@ exports[`QuoteInfoModal renders correctly 1`] = ` accessibilityRole="text" style={ { - "color": "#0376c9", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#4459ff", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > diff --git a/app/components/UI/Bridge/components/SlippageModal/SlippageModal.test.tsx b/app/components/UI/Bridge/components/SlippageModal/SlippageModal.test.tsx index e55ae530405..d4a918b0aa9 100644 --- a/app/components/UI/Bridge/components/SlippageModal/SlippageModal.test.tsx +++ b/app/components/UI/Bridge/components/SlippageModal/SlippageModal.test.tsx @@ -5,9 +5,11 @@ import { SafeAreaProvider, Metrics } from 'react-native-safe-area-context'; import renderWithProvider from '../../../../../util/test/renderWithProvider'; import { strings } from '../../../../../../locales/i18n'; import SlippageModal from './index'; +import { setSlippage } from '../../../../../core/redux/slices/bridge'; const mockNavigate = jest.fn(); const mockGoBack = jest.fn(); +const mockDispatch = jest.fn(); jest.mock('@react-navigation/native', () => { const actualReactNavigation = jest.requireActual('@react-navigation/native'); @@ -20,25 +22,33 @@ jest.mock('@react-navigation/native', () => { }; }); -const props = { - route: { - params: { - selectedSlippage: '0.5', - onSelectSlippage: jest.fn(), - }, - }, -}; +jest.mock('react-redux', () => { + const actualReactRedux = jest.requireActual('react-redux'); + return { + ...actualReactRedux, + useDispatch: () => mockDispatch, + }; +}); const initialMetrics: Metrics = { frame: { x: 0, y: 0, width: 320, height: 640 }, insets: { top: 0, left: 0, right: 0, bottom: 0 }, }; +const initialState = { + bridge: { + slippage: '0.5', + }, +}; + const renderSlippageModal = () => renderWithProvider( - + , + { + state: initialState, + }, ); describe('SlippageModal', () => { @@ -59,7 +69,7 @@ describe('SlippageModal', () => { expect(toJSON()).toMatchSnapshot(); }); - it('updates slippage value when segment is selected and sends value back when applied', () => { + it('updates slippage value when segment is selected and dispatches action when applied', () => { const { getByText, getByTestId } = renderSlippageModal(); // Click on the 3% option @@ -70,8 +80,9 @@ describe('SlippageModal', () => { const applyButton = getByText(strings('bridge.apply')); fireEvent.press(applyButton); - // Check if the callback was called with the correct value - expect(props.route.params.onSelectSlippage).toHaveBeenCalledWith('3'); + // Check if the action was dispatched with the correct value + expect(mockDispatch).toHaveBeenCalledWith(setSlippage('3')); + // Check that navigation.goBack was called expect(mockGoBack).toHaveBeenCalled(); }); diff --git a/app/components/UI/Bridge/components/SlippageModal/__snapshots__/SlippageModal.test.tsx.snap b/app/components/UI/Bridge/components/SlippageModal/__snapshots__/SlippageModal.test.tsx.snap index d2c7f448b36..7e8826671c8 100644 --- a/app/components/UI/Bridge/components/SlippageModal/__snapshots__/SlippageModal.test.tsx.snap +++ b/app/components/UI/Bridge/components/SlippageModal/__snapshots__/SlippageModal.test.tsx.snap @@ -34,7 +34,7 @@ exports[`SlippageModal renders all UI elements with the proper slippage options style={ [ { - "backgroundColor": "#00000099", + "backgroundColor": "#00000066", "bottom": 0, "left": 0, "position": "absolute", @@ -81,14 +81,14 @@ exports[`SlippageModal renders all UI elements with the proper slippage options [ { "backgroundColor": "#ffffff", - "borderColor": "#BBC0C566", + "borderColor": "#b7bbc866", "borderTopLeftRadius": 8, "borderTopRightRadius": 8, "borderWidth": 1, "maxHeight": 1334, "overflow": "hidden", "paddingBottom": 0, - "shadowColor": "#0000001A", + "shadowColor": "#0000001a", "shadowOffset": { "height": 2, "width": 0, @@ -118,7 +118,7 @@ exports[`SlippageModal renders all UI elements with the proper slippage options @@ -335,7 +335,7 @@ exports[`SlippageModal renders all UI elements with the proper slippage options "alignItems": "center", "alignSelf": "stretch", "backgroundColor": "transparent", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 16, "borderWidth": 1, "flexDirection": "row", @@ -350,12 +350,12 @@ exports[`SlippageModal renders all UI elements with the proper slippage options accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -384,7 +384,7 @@ exports[`SlippageModal renders all UI elements with the proper slippage options "alignItems": "center", "alignSelf": "stretch", "backgroundColor": "transparent", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 16, "borderWidth": 1, "flexDirection": "row", @@ -399,12 +399,12 @@ exports[`SlippageModal renders all UI elements with the proper slippage options accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -433,7 +433,7 @@ exports[`SlippageModal renders all UI elements with the proper slippage options "alignItems": "center", "alignSelf": "stretch", "backgroundColor": "transparent", - "borderColor": "#848c96", + "borderColor": "#b7bbc8", "borderRadius": 16, "borderWidth": 1, "flexDirection": "row", @@ -448,12 +448,12 @@ exports[`SlippageModal renders all UI elements with the proper slippage options accessibilityRole="text" style={ { - "color": "#141618", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#121314", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > @@ -486,7 +486,7 @@ exports[`SlippageModal renders all UI elements with the proper slippage options "alignItems": "center", "alignSelf": "flex-start", "backgroundColor": "transparent", - "borderColor": "#0376c9", + "borderColor": "#4459ff", "borderRadius": 24, "borderWidth": 1, "flex": 1, @@ -502,12 +502,12 @@ exports[`SlippageModal renders all UI elements with the proper slippage options accessibilityRole="text" style={ { - "color": "#0376c9", - "fontFamily": "EuclidCircularB-Medium", - "fontSize": 14, + "color": "#4459ff", + "fontFamily": "CentraNo1-Medium", + "fontSize": 16, "fontWeight": "500", "letterSpacing": 0, - "lineHeight": 22, + "lineHeight": 24, } } > diff --git a/app/components/UI/Bridge/components/SlippageModal/index.tsx b/app/components/UI/Bridge/components/SlippageModal/index.tsx index d145fdd8f2f..3c42adcb2ff 100644 --- a/app/components/UI/Bridge/components/SlippageModal/index.tsx +++ b/app/components/UI/Bridge/components/SlippageModal/index.tsx @@ -19,6 +19,11 @@ import { SlippageOption } from './SlippageModal.types'; import BottomSheetHeader from '../../../../../component-library/components/BottomSheets/BottomSheetHeader'; import BottomSheetFooter from '../../../../../component-library/components/BottomSheets/BottomSheetFooter'; import SegmentedControl from '../../../../../component-library/components-temp/SegmentedControl'; +import { useDispatch, useSelector } from 'react-redux'; +import { + selectSlippage, + setSlippage, +} from '../../../../../core/redux/slices/bridge'; const SLIPPAGE_OPTIONS: SlippageOption[] = [ { label: '0.5%', value: '0.5' }, @@ -27,18 +32,11 @@ const SLIPPAGE_OPTIONS: SlippageOption[] = [ { label: '10%', value: '10' }, ]; -interface SlippageModalProps { - route: { - params: { - selectedSlippage: string; - onSelectSlippage: (slippage: string) => void; - }; - }; -} +export const SlippageModal = () => { + const dispatch = useDispatch(); -export const SlippageModal = ({ route }: SlippageModalProps) => { - const { selectedSlippage, onSelectSlippage } = route.params; - const [selectedValue, setSelectedValue] = useState(selectedSlippage); + const slippage = useSelector(selectSlippage); + const [selectedValue, setSelectedValue] = useState(slippage); const theme = useTheme(); const styles = createStyles(theme); const navigation = useNavigation(); @@ -49,7 +47,7 @@ export const SlippageModal = ({ route }: SlippageModalProps) => { }; const handleApply = () => { - onSelectSlippage(selectedValue); + dispatch(setSlippage(selectedValue)); navigation.goBack(); }; diff --git a/app/components/UI/Bridge/components/Token.tsx b/app/components/UI/Bridge/components/TokenButton.tsx similarity index 97% rename from app/components/UI/Bridge/components/Token.tsx rename to app/components/UI/Bridge/components/TokenButton.tsx index a5fd6e93a60..066bdcbc544 100644 --- a/app/components/UI/Bridge/components/Token.tsx +++ b/app/components/UI/Bridge/components/TokenButton.tsx @@ -54,7 +54,7 @@ const createStyles = (params: StylesParams) => { }); }; -export const Token: React.FC = ({ +export const TokenButton: React.FC = ({ symbol, iconUrl, networkImageSource, diff --git a/app/components/UI/Bridge/components/TokenInputArea/TokenInputArea.test.tsx b/app/components/UI/Bridge/components/TokenInputArea/TokenInputArea.test.tsx index 24c5d1e1e14..4bd75e1e330 100644 --- a/app/components/UI/Bridge/components/TokenInputArea/TokenInputArea.test.tsx +++ b/app/components/UI/Bridge/components/TokenInputArea/TokenInputArea.test.tsx @@ -1,6 +1,5 @@ import { getDisplayFiatValue } from '.'; import { Hex } from '@metamask/utils'; -import { TokenI } from '../../../Tokens/types'; describe('getDisplayFiatValue', () => { const mockChainId = '0x1' as Hex; @@ -13,13 +12,8 @@ describe('getDisplayFiatValue', () => { decimals: 18, image: 'https://token1.com/logo.png', name: 'Token One', - aggregators: ['1inch'], - isETH: false, - isNative: false, - isStaked: false, balance: '1', balanceFiat: '$20000', - logo: 'https://token1.com/logo.png', tokenFiatAmount: 20000, }; @@ -60,7 +54,7 @@ describe('getDisplayFiatValue', () => { it('should return zero when amount is undefined', () => { const result = getDisplayFiatValue({ - token: mockToken as TokenI, + token: mockToken, amount: undefined, multiChainMarketData: mockMultiChainMarketData, networkConfigurationsByChainId: mockNetworkConfigurations, @@ -73,7 +67,7 @@ describe('getDisplayFiatValue', () => { it('should calculate correct fiat value for token amount', () => { const result = getDisplayFiatValue({ - token: mockToken as TokenI, + token: mockToken, amount: '1', multiChainMarketData: mockMultiChainMarketData, networkConfigurationsByChainId: mockNetworkConfigurations, @@ -87,7 +81,7 @@ describe('getDisplayFiatValue', () => { it('should return "< $0.01" for very small fiat values', () => { const result = getDisplayFiatValue({ - token: mockToken as TokenI, + token: mockToken, amount: '0.0000001', multiChainMarketData: mockMultiChainMarketData, networkConfigurationsByChainId: mockNetworkConfigurations, @@ -100,7 +94,7 @@ describe('getDisplayFiatValue', () => { it('should handle different currencies correctly', () => { const result = getDisplayFiatValue({ - token: mockToken as TokenI, + token: mockToken, amount: '1', multiChainMarketData: mockMultiChainMarketData, networkConfigurationsByChainId: mockNetworkConfigurations, @@ -114,7 +108,7 @@ describe('getDisplayFiatValue', () => { it('should handle undefined market data correctly', () => { const result = getDisplayFiatValue({ - token: mockToken as TokenI, + token: mockToken, amount: '1', multiChainMarketData: undefined, networkConfigurationsByChainId: mockNetworkConfigurations, @@ -136,7 +130,7 @@ describe('getDisplayFiatValue', () => { }; const result = getDisplayFiatValue({ - token: mockToken as TokenI, + token: mockToken, amount: '1', multiChainMarketData: noValueMarketData, networkConfigurationsByChainId: mockNetworkConfigurations, diff --git a/app/components/UI/Bridge/components/TokenInputArea/index.tsx b/app/components/UI/Bridge/components/TokenInputArea/index.tsx index 15516b070df..8ef511310ba 100644 --- a/app/components/UI/Bridge/components/TokenInputArea/index.tsx +++ b/app/components/UI/Bridge/components/TokenInputArea/index.tsx @@ -5,14 +5,14 @@ import { useStyles } from '../../../../../component-library/hooks'; import { Box } from '../../../Box/Box'; import Text, { TextColor } from '../../../../../component-library/components/Texts/Text'; import Input from '../../../../../component-library/components/Form/TextField/foundation/Input'; -import { Token } from '../Token'; +import { TokenButton } from '../TokenButton'; import { selectCurrentCurrency, selectCurrencyRates } from '../../../../../selectors/currencyRateController'; import { renderNumber, addCurrencySymbol, balanceToFiatNumber } from '../../../../../util/number'; import { selectTokenMarketData } from '../../../../../selectors/tokenRatesController'; -import { TokenI } from '../../../Tokens/types'; import { selectNetworkConfigurations } from '../../../../../selectors/networkController'; import { Hex } from '@metamask/utils'; import { ethers } from 'ethers'; +import { BridgeToken } from '../../types'; const createStyles = () => StyleSheet.create({ @@ -41,7 +41,7 @@ const createStyles = () => const formatAddress = (address?: string) => address ? `${address.slice(0, 6)}...${address.slice(-4)}` : undefined; interface GetDisplayFiatValueParams { - token: TokenI | undefined; + token: BridgeToken | undefined; amount: string | undefined; multiChainMarketData: Record> | undefined; networkConfigurationsByChainId: Record; @@ -85,7 +85,7 @@ export enum TokenInputAreaType { } interface TokenInputAreaProps { amount?: string; - token?: TokenI; + token?: BridgeToken; tokenBalance?: string; networkImageSource?: ImageSourcePropType; networkName?: string; @@ -149,7 +149,7 @@ export const TokenInputArea: React.FC = ({ testID={`${testID}-input`} /> - +const createStyles = ({ + theme, + vars, +}: { + theme: Theme; + vars: { isSelected: boolean }; +}) => StyleSheet.create({ - tokenIcon: { - width: 40, - height: 40, - }, tokenInfo: { flex: 1, marginLeft: 8, }, - infoButton: { - marginRight: 12, - }, container: { - backgroundColor: vars.isSelected ? theme.colors.primary.muted : theme.colors.background.default, + backgroundColor: vars.isSelected + ? theme.colors.primary.muted + : theme.colors.background.default, padding: 4, }, selectedIndicator: { @@ -46,15 +58,40 @@ const createStyles = ({ theme, vars }: { theme: Theme, vars: { isSelected: boole borderRadius: 8, backgroundColor: theme.colors.primary.default, }, + itemWrapper: { + flex: 1, + flexDirection: 'row', + paddingHorizontal: 15, + paddingVertical: 10, + alignItems: 'flex-start', + }, + balance: { + flex: 1, + alignItems: 'flex-end', + }, + skeleton: { + width: 50, + }, + secondaryBalance: { + color: theme.colors.text.alternative, + paddingHorizontal: 0, + ...fontStyles.normal, + textTransform: 'uppercase', + }, + badgeWrapper: { + // override the BadgeWrapper alignSelf: 'flex-start', let parent control the alignment + alignSelf: undefined, + }, }); interface TokenSelectorItemProps { - token: TokenIWithFiatAmount; - onPress: (token: TokenIWithFiatAmount) => void; + token: BridgeToken; + onPress: (token: BridgeToken) => void; networkName: string; networkImageSource?: ImageSourcePropType; - shouldShowBalance?: boolean; isSelected?: boolean; + shouldShowBalance?: boolean; + children?: React.ReactNode; } export const TokenSelectorItem: React.FC = ({ @@ -62,79 +99,97 @@ export const TokenSelectorItem: React.FC = ({ onPress, networkName, networkImageSource, - shouldShowBalance = true, isSelected = false, + shouldShowBalance = true, + children, }) => { const { styles } = useStyles(createStyles, { isSelected }); - const navigation = useNavigation(); const fiatValue = token.balanceFiat; - const balanceWithSymbol = `${token.balance} ${token.symbol}`; + const balanceWithSymbol = token.balance + ? `${token.balance} ${token.symbol}` + : undefined; - // Open the asset details screen as a bottom sheet - const handleInfoButtonPress = () => navigation.navigate('Asset', { ...token }); + const isNative = token.address === ethers.constants.AddressZero; + + const balance = shouldShowBalance ? fiatValue : undefined; + const secondaryBalance = shouldShowBalance ? balanceWithSymbol : undefined; return ( {isSelected && } - onPress(token)} - balance={shouldShowBalance ? fiatValue : undefined} - secondaryBalance={shouldShowBalance ? balanceWithSymbol : undefined} + style={styles.itemWrapper} + {...generateTestId(Platform, getAssetTestId(token.symbol))} > - - } - > - {token.isNative ? ( - - ) : ( - - )} - - - - {token.symbol} - - - {token.name} - + + {/* Token Icon */} + + } + > + {isNative ? ( + + ) : ( + + )} + + + {/* Token symbol and name */} + + {token.symbol} + + {token.name} + + + + {/* Token balance and fiat value */} + + {balance && + (balance === TOKEN_BALANCE_LOADING || + balance === TOKEN_BALANCE_LOADING_UPPERCASE ? ( + + ) : ( + {balance} + ))} + {secondaryBalance ? ( + secondaryBalance === TOKEN_BALANCE_LOADING || + secondaryBalance === TOKEN_BALANCE_LOADING_UPPERCASE ? ( + + ) : ( + {secondaryBalance} + ) + ) : null} + - - {!shouldShowBalance && ( - - )} + + + {children} ); }; diff --git a/app/components/UI/Bridge/hooks/useDestinationTokens.tsx b/app/components/UI/Bridge/hooks/useDestinationTokens.tsx deleted file mode 100644 index dae1974ba00..00000000000 --- a/app/components/UI/Bridge/hooks/useDestinationTokens.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { useTokensWithBalance, TokenIWithFiatAmount } from './useTokensWithBalance'; -import { useSelector } from 'react-redux'; -import { selectSelectedDestChainId, selectSourceToken } from '../../../../core/redux/slices/bridge'; -import { Hex } from '@metamask/utils'; -import { useMemo } from 'react'; - -// TODO get top tokens from BridgeController -export const useDestinationTokens: () => TokenIWithFiatAmount[] = () => { - const selectedDestChainId = useSelector(selectSelectedDestChainId); - const selectedSourceToken = useSelector(selectSourceToken); - - const tokensWithBalance = useTokensWithBalance({ chainIds: [selectedDestChainId as Hex] }); - - const filteredTokens = useMemo(() => tokensWithBalance.filter((token) => { - const isSelectedSourceToken = token.address === selectedSourceToken?.address && token.chainId === selectedSourceToken?.chainId; - - return !isSelectedSourceToken; - }), [tokensWithBalance, selectedSourceToken]); - - return filteredTokens; -}; diff --git a/app/components/UI/Bridge/hooks/useSourceTokens.ts b/app/components/UI/Bridge/hooks/useSourceTokens.ts deleted file mode 100644 index 1b349604291..00000000000 --- a/app/components/UI/Bridge/hooks/useSourceTokens.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { TokenIWithFiatAmount, useTokensWithBalance } from './useTokensWithBalance'; -import { useSelector } from 'react-redux'; -import { selectSelectedSourceChainIds, selectDestToken } from '../../../../core/redux/slices/bridge'; -import { Hex } from '@metamask/utils'; -import { useMemo } from 'react'; -// TODO get top tokens from BridgeController -export const useSourceTokens: () => TokenIWithFiatAmount[] = () => { - const selectedSourceChainIds = useSelector(selectSelectedSourceChainIds); - const selectedDestToken = useSelector(selectDestToken); - - const tokensWithBalance = useTokensWithBalance({ chainIds: selectedSourceChainIds as Hex[] }); - - const filteredTokens = useMemo(() => tokensWithBalance.filter((token) => { - const isSelectedDestToken = token.address === selectedDestToken?.address && token.chainId === selectedDestToken?.chainId; - - return !isSelectedDestToken; - }), [tokensWithBalance, selectedDestToken]); - - return filteredTokens; -}; diff --git a/app/components/UI/Bridge/hooks/useTokenSearch/index.ts b/app/components/UI/Bridge/hooks/useTokenSearch/index.ts index c9265a27926..3622da2f56b 100644 --- a/app/components/UI/Bridge/hooks/useTokenSearch/index.ts +++ b/app/components/UI/Bridge/hooks/useTokenSearch/index.ts @@ -1,16 +1,17 @@ import { useMemo, useState } from 'react'; import Fuse from 'fuse.js'; -import { TokenIWithFiatAmount } from '../useTokensWithBalance'; +import { BridgeToken } from '../../types'; + const MAX_TOKENS_RESULTS = 20; interface UseTokenSearchProps { - tokens: TokenIWithFiatAmount[]; + tokens: BridgeToken[]; } interface UseTokenSearchResult { searchString: string; setSearchString: (text: string) => void; - searchResults: TokenIWithFiatAmount[]; + searchResults: BridgeToken[]; } export function useTokenSearch({ tokens }: UseTokenSearchProps): UseTokenSearchResult { @@ -33,8 +34,8 @@ export function useTokenSearch({ tokens }: UseTokenSearchProps): UseTokenSearchR const tokenSearchResults = useMemo( () => (tokenFuse.search(searchString)).slice(0, MAX_TOKENS_RESULTS).sort((a, b) => { // Sort results by balance fiat in descending order - const balanceA = a.tokenFiatAmount; - const balanceB = b.tokenFiatAmount; + const balanceA = a.tokenFiatAmount ?? 0; + const balanceB = b.tokenFiatAmount ?? 0; return balanceB - balanceA; }), [searchString, tokenFuse], diff --git a/app/components/UI/Bridge/hooks/useTokenSearch/useTokenSearch.test.ts b/app/components/UI/Bridge/hooks/useTokenSearch/useTokenSearch.test.ts index 38918f3dc2f..ac0c1c3ea92 100644 --- a/app/components/UI/Bridge/hooks/useTokenSearch/useTokenSearch.test.ts +++ b/app/components/UI/Bridge/hooks/useTokenSearch/useTokenSearch.test.ts @@ -1,10 +1,11 @@ import { renderHook, act } from '@testing-library/react-hooks'; import { useTokenSearch } from '.'; -import { TokenIWithFiatAmount } from '../useTokensWithBalance'; +import { BridgeToken } from '../../types'; +import { Hex } from '@metamask/utils'; describe('useTokenSearch', () => { // Mock token data - const mockTokens: TokenIWithFiatAmount[] = [ + const mockTokens: BridgeToken[] = [ { address: '0x1', symbol: 'ETH', @@ -13,10 +14,8 @@ describe('useTokenSearch', () => { balance: '1.23', balanceFiat: '$2000.00', tokenFiatAmount: 2000.00, - aggregators: [], image: 'https://example.com/eth.png', - logo: 'https://example.com/eth.png', - isETH: true, + chainId: '0x1', }, { address: '0x2', @@ -26,10 +25,8 @@ describe('useTokenSearch', () => { balance: '100.123', balanceFiat: '$100.123', tokenFiatAmount: 100.123, - aggregators: [], image: 'https://example.com/usdc.png', - logo: 'https://example.com/usdc.png', - isETH: false, + chainId: '0x1', }, { address: '0x3', @@ -39,10 +36,8 @@ describe('useTokenSearch', () => { balance: '0', balanceFiat: '$0.00', tokenFiatAmount: 0.00, - aggregators: [], image: 'https://example.com/dai.png', - logo: 'https://example.com/dai.png', - isETH: false, + chainId: '0x1', }, { address: '0x4', @@ -52,10 +47,8 @@ describe('useTokenSearch', () => { balance: '20.1', balanceFiat: '$20.1', tokenFiatAmount: 20.1, - aggregators: [], image: 'https://example.com/usdt.png', - logo: 'https://example.com/usdt.png', - isETH: false, + chainId: '0x1', }, ]; @@ -139,7 +132,7 @@ describe('useTokenSearch', () => { }); it('should handle undefined token list', () => { - const { result } = renderHook(() => useTokenSearch({ tokens: undefined as unknown as TokenIWithFiatAmount[] })); + const { result } = renderHook(() => useTokenSearch({ tokens: undefined as unknown as BridgeToken[] })); act(() => { result.current.setSearchString('ETH'); @@ -158,11 +151,9 @@ describe('useTokenSearch', () => { balance: '0', balanceFiat: '$0.00', tokenFiatAmount: 0, - aggregators: [], image: `https://example.com/tkn${i}.png`, - logo: `https://example.com/tkn${i}.png`, - isETH: false, - })) as TokenIWithFiatAmount[]; + chainId: '0x1' as Hex, + })); const { result } = renderHook(() => useTokenSearch({ tokens: largeTokenList })); diff --git a/app/components/UI/Bridge/hooks/useTokens.ts b/app/components/UI/Bridge/hooks/useTokens.ts new file mode 100644 index 00000000000..5a273441618 --- /dev/null +++ b/app/components/UI/Bridge/hooks/useTokens.ts @@ -0,0 +1,58 @@ +import { useTokensWithBalance } from './useTokensWithBalance'; +import { Hex } from '@metamask/utils'; +import { useMemo } from 'react'; +import { useTopTokens } from './useTopTokens'; +import { BridgeToken } from '../types'; + +interface UseTokensProps { + topTokensChainId?: Hex; + balanceChainIds?: Hex[]; + tokensToExclude?: { address: string; chainId: Hex }[]; +} + +/** + * Hook to get tokens for the bridge + * @param {Object} params - The parameters object + * @param {Hex} params.topTokensChainId - The chain ID of the top tokens + * @param {Hex[]} params.balanceChainIds - The chain IDs you want to get the balance for + * @param {TokenI[]} params.tokensToExclude - The tokens to exclude + * @returns {BridgeToken[]} Array of tokens with fiat balances + */ +export function useTokens({ + topTokensChainId, + balanceChainIds, + tokensToExclude +}: UseTokensProps): { tokens: BridgeToken[], pending: boolean } { + const tokensWithBalance = useTokensWithBalance({ + chainIds: balanceChainIds as Hex[] + }); + + const { topTokens, pending } = useTopTokens({ chainId: topTokensChainId }); + + const topTokensFiltered = useMemo(() => + topTokens + // filter out tokens that are already in the tokensWithBalance array + ?.filter((token) => !tokensWithBalance.some( + (t) => t.address === token.address && t.chainId === token.chainId + )) ?? [], + [topTokens, tokensWithBalance] + ); + + const uniqueTokens = useMemo( + () => [...tokensWithBalance, ...topTokensFiltered], + [tokensWithBalance, topTokensFiltered] + ); + + const filteredTokens = useMemo( + () => uniqueTokens.filter((token) => { + // filter out tokens that are in the tokensToExclude array + const isSelectedToken = tokensToExclude?.some( + (t) => t.address === token.address && t.chainId === token.chainId + ); + return !isSelectedToken; + }), + [uniqueTokens, tokensToExclude] + ); + + return { tokens: filteredTokens, pending }; +} diff --git a/app/components/UI/Bridge/hooks/useTokensWithBalance/index.ts b/app/components/UI/Bridge/hooks/useTokensWithBalance/index.ts index b1d4fa3fa54..2c119ecdf10 100644 --- a/app/components/UI/Bridge/hooks/useTokensWithBalance/index.ts +++ b/app/components/UI/Bridge/hooks/useTokensWithBalance/index.ts @@ -16,8 +16,7 @@ import { } from '../../../Tokens/util'; import { selectTokenSortConfig } from '../../../../../selectors/preferencesController'; import { selectAccountTokensAcrossChains } from '../../../../../selectors/multichain'; - -export type TokenIWithFiatAmount = TokenI & { tokenFiatAmount: number }; +import { BridgeToken } from '../../types'; interface CalculateFiatBalancesParams { assets: TokenI[]; @@ -101,13 +100,13 @@ export const calculateBalances = ({ * Hook to get tokens with fiat balances * @param {Object} params - The parameters object * @param {Hex[]} params.chainIds - Array of chain IDs to filter by - * @returns {TokenIWithFiatAmount[]} Array of tokens (native and non-native) with sortable fiat balances + * @returns {BridgeToken[]} Array of tokens (native and non-native) with sortable fiat balances */ export const useTokensWithBalance: ({ chainIds, }: { chainIds: Hex[]; -}) => TokenIWithFiatAmount[] = ({ chainIds }) => { +}) => BridgeToken[] = ({ chainIds }) => { const tokenSortConfig = useSelector(selectTokenSortConfig); const currentCurrency = useSelector(selectCurrentCurrency); const selectedInternalAccountAddress = useSelector( @@ -142,13 +141,19 @@ export const useTokensWithBalance: ({ currentCurrency, selectedAddress: selectedInternalAccountAddress, }); - const properTokens = allAccountTokens.map((token, i) => ({ - ...token, - tokenFiatAmount: balances[i].tokenFiatAmount ?? 0, - balance: balances[i].balance, - balanceFiat: balances[i].balanceFiat, - symbol: token.isETH ? 'ETH' : token.symbol, // TODO: not sure why symbol is ETHEREUM, will also break the token icon for ETH - })); + const properTokens: BridgeToken[] = allAccountTokens + .filter((token) => Boolean(token.chainId)) // Ensure token has a chainId + .map((token, i) => ({ + address: token.address, + name: token.name, + decimals: token.decimals, + symbol: token.isETH ? 'ETH' : token.symbol, // TODO: not sure why symbol is ETHEREUM, will also break the token icon for ETH + chainId: token.chainId as Hex, + image: token.image, + tokenFiatAmount: balances[i].tokenFiatAmount ?? 0, + balance: balances[i].balance, + balanceFiat: balances[i].balanceFiat, + })); return sortAssets(properTokens, tokenSortConfig); }, [ accountTokensAcrossChains, diff --git a/app/components/UI/Bridge/hooks/useTokensWithBalance/useTokensWithBalance.test.ts b/app/components/UI/Bridge/hooks/useTokensWithBalance/useTokensWithBalance.test.ts index 8ae9f2b3dad..81e29c04326 100644 --- a/app/components/UI/Bridge/hooks/useTokensWithBalance/useTokensWithBalance.test.ts +++ b/app/components/UI/Bridge/hooks/useTokensWithBalance/useTokensWithBalance.test.ts @@ -3,7 +3,10 @@ import { useTokensWithBalance } from '.'; import { constants } from 'ethers'; import { waitFor } from '@testing-library/react-native'; import { Hex } from '@metamask/utils'; -import { BridgeFeatureFlagsKey } from '@metamask/bridge-controller'; +import { + BridgeFeatureFlagsKey, + formatChainIdToCaip, +} from '@metamask/bridge-controller'; // Mock dependencies jest.mock('../../../../../util/networks', () => ({ @@ -31,8 +34,14 @@ describe('useTokensWithBalance', () => { bridgeFeatureFlags: { [BridgeFeatureFlagsKey.MOBILE_CONFIG]: { chains: { - '0x1': { isActiveSrc: true, isActiveDest: true }, - '0xa': { isActiveSrc: true, isActiveDest: true }, + [formatChainIdToCaip(mockChainId)]: { + isActiveSrc: true, + isActiveDest: true, + }, + [formatChainIdToCaip(optimismChainId)]: { + isActiveSrc: true, + isActiveDest: true, + }, }, }, }, @@ -296,20 +305,24 @@ describe('useTokensWithBalance', () => { }); it('should include native token with correct properties', async () => { - const { result } = renderHookWithProvider(() => useTokensWithBalance({ - chainIds: [mockChainId, optimismChainId], - }), { - state: initialState, - }); + const { result } = renderHookWithProvider( + () => + useTokensWithBalance({ + chainIds: [mockChainId, optimismChainId], + }), + { + state: initialState, + }, + ); await waitFor(() => { - const nativeToken = result.current.find(token => token.isNative && token.chainId === mockChainId); + const nativeToken = result.current.find(token => token.address === constants.AddressZero && token.chainId === mockChainId); expect(nativeToken).toMatchObject({ address: constants.AddressZero, symbol: 'ETH', name: 'Ethereum', decimals: 18, - isNative: true, + chainId: mockChainId, balance: '3', balanceFiat: '$6000', tokenFiatAmount: 6000, @@ -318,16 +331,24 @@ describe('useTokensWithBalance', () => { }); it('should show correct balances and fiat values for tokens', async () => { - const { result } = renderHookWithProvider(() => useTokensWithBalance({ - chainIds: [mockChainId, optimismChainId], - }), { - state: initialState, - }); + const { result } = renderHookWithProvider( + () => + useTokensWithBalance({ + chainIds: [mockChainId, optimismChainId], + }), + { + state: initialState, + }, + ); await waitFor(() => { // Ethereum chain tokens - const token1 = result.current.find((t) => t.address === token1Address && t.chainId === mockChainId); - const token2 = result.current.find((t) => t.address === token2Address && t.chainId === mockChainId); + const token1 = result.current.find( + (t) => t.address === token1Address && t.chainId === mockChainId, + ); + const token2 = result.current.find( + (t) => t.address === token2Address && t.chainId === mockChainId, + ); expect(token1).toMatchObject({ balance: '1', @@ -342,7 +363,7 @@ describe('useTokensWithBalance', () => { }); // Optimism chain tokens - const optimismNative = result.current.find(token => token.isNative && token.chainId === optimismChainId); + const optimismNative = result.current.find(token => token.address === constants.AddressZero && token.chainId === optimismChainId); expect(optimismNative).toMatchObject({ address: constants.AddressZero, symbol: 'ETH', @@ -366,15 +387,19 @@ describe('useTokensWithBalance', () => { }); it('should only show tokens for selected chains', async () => { - const { result } = renderHookWithProvider(() => useTokensWithBalance({ - chainIds: [mockChainId], - }), { - state: initialState, - }); + const { result } = renderHookWithProvider( + () => + useTokensWithBalance({ + chainIds: [mockChainId], + }), + { + state: initialState, + }, + ); await waitFor(() => { // Ethereum tokens should be present - const ethereumNative = result.current.find(token => token.isNative && token.chainId === mockChainId); + const ethereumNative = result.current.find(token => token.address === constants.AddressZero && token.chainId === mockChainId); const token1 = result.current.find(t => t.address === token1Address); const token2 = result.current.find(t => t.address === token2Address); @@ -383,7 +408,7 @@ describe('useTokensWithBalance', () => { expect(token2).toBeTruthy(); // Optimism tokens should not be present - const optimismNative = result.current.find(token => token.isNative && token.chainId === optimismChainId); + const optimismNative = result.current.find(token => token.address === constants.AddressZero && token.chainId === optimismChainId); const token3 = result.current.find(t => t.address === token3Address); expect(optimismNative).toBeUndefined(); @@ -417,11 +442,15 @@ describe('useTokensWithBalance', () => { }, }; - const { result } = renderHookWithProvider(() => useTokensWithBalance({ - chainIds: [mockChainId, optimismChainId], - }), { - state: stateWithSmallBalance, - }); + const { result } = renderHookWithProvider( + () => + useTokensWithBalance({ + chainIds: [mockChainId, optimismChainId], + }), + { + state: stateWithSmallBalance, + }, + ); await waitFor(() => { const token1 = result.current.find((t) => t.address === token1Address); diff --git a/app/components/UI/Bridge/hooks/useTopTokens/index.ts b/app/components/UI/Bridge/hooks/useTopTokens/index.ts new file mode 100644 index 00000000000..36c23989178 --- /dev/null +++ b/app/components/UI/Bridge/hooks/useTopTokens/index.ts @@ -0,0 +1,104 @@ +import { BRIDGE_PROD_API_BASE_URL, BridgeClientId, fetchBridgeTokens, formatChainIdToHex } from '@metamask/bridge-controller'; +import { useAsyncResult } from '../../../../hooks/useAsyncResult'; +import { Hex } from '@metamask/utils'; +import { handleFetch, toChecksumHexAddress } from '@metamask/controller-utils'; +import { BridgeToken } from '../../types'; +import { useEffect, useMemo, useRef } from 'react'; +import Engine from '../../../../../core/Engine'; +import { useSelector } from 'react-redux'; +import Logger from '../../../../../util/Logger'; +import { selectChainCache } from '../../../../../reducers/swaps'; +import { SwapsControllerState } from '@metamask/swaps-controller'; +interface UseTopTokensProps { + chainId?: Hex; +} + +export const useTopTokens = ({ chainId }: UseTopTokensProps): { topTokens: BridgeToken[] | undefined, pending: boolean } => { + const swapsChainCache: SwapsControllerState['chainCache'] = useSelector(selectChainCache); + const swapsTopAssets = useMemo( + () => (chainId ? swapsChainCache[chainId]?.topAssets : null), + [chainId, swapsChainCache], + ); + const swapsTopAssetsPending = !swapsTopAssets; + + const cachedBridgeTokens = useRef>>({}); + + // Get the top assets from the Swaps API + useEffect(() => { + (async () => { + const { SwapsController } = Engine.context; + try { + if (chainId) { + // Maintains an internal cache, will fetch if past internal threshold + await SwapsController.fetchTopAssetsWithCache({ + chainId, + }); + } + } catch (error: unknown) { + Logger.error( + error as Error, + 'Swaps: Error while fetching top assets', + ); + } + })(); + }, [chainId]); + + // Get the token data from the bridge API + const { value: bridgeTokens, pending: bridgeTokensPending } = useAsyncResult(async () => { + if (!chainId) { + return {}; + } + + if (cachedBridgeTokens.current[chainId]) { + return cachedBridgeTokens.current[chainId]; + } + + const rawBridgeAssets = await fetchBridgeTokens( + chainId, + BridgeClientId.MOBILE, + handleFetch, + BRIDGE_PROD_API_BASE_URL, + ); + + // Convert from BridgeAsset to BridgeToken + const bridgeTokenObj: Record = {}; + Object.keys(rawBridgeAssets).forEach((key) => { + const bridgeAsset = rawBridgeAssets[key]; + + bridgeTokenObj[key] = { + address: bridgeAsset.address, + symbol: bridgeAsset.symbol, + name: bridgeAsset.name, + image: bridgeAsset.iconUrl || bridgeAsset.icon, + decimals: bridgeAsset.decimals, + chainId: formatChainIdToHex(bridgeAsset.chainId), // TODO handle solana properly + }; + }); + + cachedBridgeTokens.current = { + ...cachedBridgeTokens.current, + [chainId]: bridgeTokenObj, + }; + + return bridgeTokenObj; + }, [chainId]); + + // Merge the top assets from the Swaps API with the token data from the bridge API + const topTokens = useMemo(() => { + if (!bridgeTokens || !swapsTopAssets) { + return []; + } + + const top = swapsTopAssets.map((asset) => { + const candidateBridgeToken = bridgeTokens[asset.address.toLowerCase()] + || bridgeTokens[toChecksumHexAddress(asset.address)]; + + return candidateBridgeToken; + }) + .filter(Boolean) as BridgeToken[]; + + return top; + }, [bridgeTokens, swapsTopAssets]); + + return { topTokens, pending: chainId ? (bridgeTokensPending || swapsTopAssetsPending) : false }; +}; diff --git a/app/components/UI/Bridge/hooks/useTopTokens/useTopTokens.test.ts b/app/components/UI/Bridge/hooks/useTopTokens/useTopTokens.test.ts new file mode 100644 index 00000000000..acda34476d6 --- /dev/null +++ b/app/components/UI/Bridge/hooks/useTopTokens/useTopTokens.test.ts @@ -0,0 +1,145 @@ +import { renderHookWithProvider } from '../../../../../util/test/renderWithProvider'; +import { useTopTokens } from '.'; +import { waitFor } from '@testing-library/react-native'; +import { Hex } from '@metamask/utils'; +import { BridgeClientId, BRIDGE_PROD_API_BASE_URL, fetchBridgeTokens } from '@metamask/bridge-controller'; +import { handleFetch } from '@metamask/controller-utils'; +import { initialState } from '../../_mocks_/initialState'; +import { BridgeToken } from '../../types'; + +// Mock dependencies +jest.mock('@metamask/bridge-controller', () => ({ + ...jest.requireActual('@metamask/bridge-controller'), + fetchBridgeTokens: jest.fn(), +})); + +describe('useTopTokens', () => { + const mockChainId = '0x1' as Hex; + const mockBridgeToken1: BridgeToken = { + address: '0x0000000000000000000000000000000000000001', + symbol: 'TOKEN1', + name: 'Token One', + image: 'https://token1.com/logo.png', + decimals: 18, + chainId: '0x1', + }; + + const mockBridgeToken2: BridgeToken = { + address: '0x0000000000000000000000000000000000000002', + symbol: 'HELLO', + name: 'Hello Token', + image: 'https://token2.com/logo.png', + decimals: 18, + chainId: '0x1', + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should return empty array when no chainId is provided', () => { + const { result } = renderHookWithProvider(() => useTopTokens({}), { + state: initialState, + }); + + expect(result.current.topTokens).toEqual([]); + expect(result.current.pending).toBe(false); + }); + + it('should fetch and merge top tokens from Swaps and Bridge APIs', async () => { + // Mock Bridge API response with both tokens + const mockBridgeResponse = { + [mockBridgeToken1.address.toLowerCase()]: { + address: mockBridgeToken1.address, + symbol: mockBridgeToken1.symbol, + name: mockBridgeToken1.name, + iconUrl: mockBridgeToken1.image, + decimals: mockBridgeToken1.decimals, + chainId: mockBridgeToken1.chainId, + assetId: 'token1-asset-id', + }, + [mockBridgeToken2.address.toLowerCase()]: { + address: mockBridgeToken2.address, + symbol: mockBridgeToken2.symbol, + name: mockBridgeToken2.name, + iconUrl: mockBridgeToken2.image, + decimals: mockBridgeToken2.decimals, + chainId: mockBridgeToken2.chainId, + assetId: 'token2-asset-id', + }, + }; + + // Mock the Bridge API call + (fetchBridgeTokens as jest.Mock).mockResolvedValue(mockBridgeResponse); + + const { result } = renderHookWithProvider( + () => useTopTokens({ chainId: mockChainId }), + { state: initialState } + ); + + // Initial state should be pending + expect(result.current.pending).toBe(true); + + await waitFor(() => { + expect(result.current.pending).toBe(false); + expect(result.current.topTokens).toHaveLength(2); // From initialState's SwapsController.topAssets + + // Verify both tokens are present and have correct data + const tokens = result.current.topTokens || []; + expect(tokens[0]).toMatchObject({ + address: mockBridgeToken1.address, + symbol: mockBridgeToken1.symbol, + name: mockBridgeToken1.name, + image: mockBridgeToken1.image, + decimals: mockBridgeToken1.decimals, + chainId: mockBridgeToken1.chainId, + }); + + expect(tokens[1]).toMatchObject({ + address: mockBridgeToken2.address, + symbol: mockBridgeToken2.symbol, + name: mockBridgeToken2.name, + image: mockBridgeToken2.image, + decimals: mockBridgeToken2.decimals, + chainId: mockBridgeToken2.chainId, + }); + }); + + // Verify Bridge API was called with correct parameters + expect(fetchBridgeTokens).toHaveBeenCalledWith( + mockChainId, + BridgeClientId.MOBILE, + handleFetch, + BRIDGE_PROD_API_BASE_URL + ); + }); + + it('should handle Bridge API errors gracefully', async () => { + // Mock Bridge API error + (fetchBridgeTokens as jest.Mock).mockRejectedValue(new Error('Bridge API Error')); + + const { result } = renderHookWithProvider( + () => useTopTokens({ chainId: mockChainId }), + { state: initialState } + ); + + await waitFor(() => { + expect(result.current.pending).toBe(false); + expect(result.current.topTokens).toEqual([]); + }); + }); + + it('should handle missing Bridge token data gracefully', async () => { + (fetchBridgeTokens as jest.Mock).mockResolvedValue({}); + + const { result } = renderHookWithProvider( + () => useTopTokens({ chainId: mockChainId }), + { state: initialState } + ); + + await waitFor(() => { + expect(result.current.pending).toBe(false); + expect(result.current.topTokens).toEqual([]); + }); + }); +}); diff --git a/app/components/UI/Bridge/index.test.tsx b/app/components/UI/Bridge/index.test.tsx index ec7c575e3c3..5fd393c6288 100644 --- a/app/components/UI/Bridge/index.test.tsx +++ b/app/components/UI/Bridge/index.test.tsx @@ -1,12 +1,22 @@ -import { renderScreen, DeepPartial } from '../../../util/test/renderWithProvider'; +import { + renderScreen, + DeepPartial, +} from '../../../util/test/renderWithProvider'; import { backgroundState } from '../../../util/test/initial-root-state'; import { RootState } from '../../../reducers'; import BridgeView from '../Bridge'; import { fireEvent, waitFor } from '@testing-library/react-native'; import Routes from '../../../constants/navigation/Routes'; -import { BridgeState, setDestToken, setSourceToken } from '../../../core/redux/slices/bridge'; +import { + BridgeState, + setDestToken, + setSourceToken, +} from '../../../core/redux/slices/bridge'; import { Hex } from '@metamask/utils'; -import { BridgeFeatureFlagsKey } from '@metamask/bridge-controller'; +import { + BridgeFeatureFlagsKey, + formatChainIdToCaip, +} from '@metamask/bridge-controller'; import { ethers } from 'ethers'; // TODO remove this mock once we have a real implementation @@ -23,7 +33,9 @@ jest.mock('../../../core/Engine', () => ({ })); jest.mock('../../../core/redux/slices/bridge', () => { - const actualBridgeSlice = jest.requireActual('../../../core/redux/slices/bridge'); + const actualBridgeSlice = jest.requireActual( + '../../../core/redux/slices/bridge', + ); return { __esModule: true, ...actualBridgeSlice, @@ -70,10 +82,7 @@ jest.mock('@react-navigation/native', () => { // Mock useLatestBalance hook jest.mock('./hooks/useLatestBalance', () => ({ - useLatestBalance: jest.fn().mockImplementation(({ - address, - chainId, - }) => { + useLatestBalance: jest.fn().mockImplementation(({ address, chainId }) => { if (!address || !chainId) return undefined; // Need to do this due to this error: "The module factory of `jest.mock()` is not allowed to reference any out-of-scope variables."" @@ -101,8 +110,14 @@ describe('BridgeView', () => { bridgeFeatureFlags: { [BridgeFeatureFlagsKey.MOBILE_CONFIG]: { chains: { - '0x1': { isActiveSrc: true, isActiveDest: true }, - '0xa': { isActiveSrc: true, isActiveDest: true }, + [formatChainIdToCaip(mockChainId)]: { + isActiveSrc: true, + isActiveDest: true, + }, + [formatChainIdToCaip(optimismChainId)]: { + isActiveSrc: true, + isActiveDest: true, + }, }, }, }, @@ -506,28 +521,20 @@ describe('BridgeView', () => { aggregators: [], balance: '0.31281', balanceFiat: '930.56676 cad', - chainId: '0x1', + chainId: '0x1' as Hex, decimals: 18, image: '', - isETH: true, - isNative: true, - isStaked: false, - logo: '../images/eth-logo-new.png', name: 'Ethereum', symbol: 'ETH', - ticker: 'ETH', }, destToken: { address: token2Address, aggregators: [], balance: '7.75388', balanceFiat: '11.07915 cad', - chainId: '0x1', + chainId: '0x1' as Hex, decimals: 6, image: 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.png', - isETH: false, - isNative: false, - isStaked: false, symbol: 'USDC', }, }, @@ -544,8 +551,12 @@ describe('BridgeView', () => { const arrowButton = getByTestId('arrow-button'); fireEvent.press(arrowButton); - expect(setSourceToken).toHaveBeenCalledWith(initialStateWithTokens.bridge.destToken); - expect(setDestToken).toHaveBeenCalledWith(initialStateWithTokens.bridge.sourceToken); + expect(setSourceToken).toHaveBeenCalledWith( + initialStateWithTokens.bridge.destToken, + ); + expect(setDestToken).toHaveBeenCalledWith( + initialStateWithTokens.bridge.sourceToken, + ); }); describe('Bottom Content', () => { @@ -628,24 +639,25 @@ describe('BridgeView', () => { { name: Routes.BRIDGE.ROOT, }, - { state: { - ...initialState, - bridge: { - ...initialState.bridge, - sourceAmount: '1.0', - destToken: { - address: token2Address, - symbol: 'TOKEN2', - decimals: 18, - image: 'https://token2.com/logo.png', - name: 'Token Two', - chainId: optimismChainId, + { + state: { + ...initialState, + bridge: { + ...initialState.bridge, + sourceAmount: '1.0', + destToken: { + address: token2Address, + symbol: 'TOKEN2', + decimals: 18, + image: 'https://token2.com/logo.png', + name: 'Token Two', + chainId: optimismChainId, + }, + selectedDestChainId: optimismChainId, + selectedSourceChainIds: [mockChainId, optimismChainId], }, - selectedDestChainId: optimismChainId, - selectedSourceChainIds: [mockChainId, optimismChainId], }, }, - }, ); const continueButton = getByText('Continue'); diff --git a/app/components/UI/Bridge/index.tsx b/app/components/UI/Bridge/index.tsx index 0c7cf651c5d..26888494daa 100644 --- a/app/components/UI/Bridge/index.tsx +++ b/app/components/UI/Bridge/index.tsx @@ -1,11 +1,10 @@ -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useEffect, useMemo } from 'react'; import { StyleSheet } from 'react-native'; import { useSelector, useDispatch } from 'react-redux'; import ScreenView from '../../Base/ScreenView'; import Keypad from '../../Base/Keypad'; import { TokenInputArea, TokenInputAreaType } from './components/TokenInputArea'; import Button, { - ButtonSize, ButtonVariants, } from '../../../component-library/components/Buttons/Button'; import { useStyles } from '../../../component-library/hooks'; @@ -44,6 +43,7 @@ import { Hex } from '@metamask/utils'; import Routes from '../../../constants/navigation/Routes'; import { selectBasicFunctionalityEnabled } from '../../../selectors/settings'; import ButtonIcon from '../../../component-library/components/Buttons/ButtonIcon'; +import QuoteDetailsCard from './components/QuoteDetailsCard'; const createStyles = (params: { theme: Theme }) => { const { theme } = params; @@ -92,13 +92,19 @@ const createStyles = (params: { theme: Theme }) => { textAlignVertical: 'center', paddingTop: 1, }, + quoteContainer: { + paddingHorizontal: 24, + paddingVertical: 24, + }, }); }; // We get here through handleBridgeNavigation in AssetOverview and WalletActions const BridgeView = () => { // The same as getUseExternalServices in Extension - const isBasicFunctionalityEnabled = useSelector(selectBasicFunctionalityEnabled); + const isBasicFunctionalityEnabled = useSelector( + selectBasicFunctionalityEnabled, + ); useEffect(() => { const setBridgeFeatureFlags = async () => { @@ -128,29 +134,36 @@ const BridgeView = () => { const destAmount = useSelector(selectDestAmount); const destChainId = useSelector(selectSelectedDestChainId); - // Add state for slippage - const [slippage, setSlippage] = useState('0.5'); - const latestSourceBalance = useLatestBalance({ address: sourceToken?.address, decimals: sourceToken?.decimals, chainId: sourceToken?.chainId as Hex, - balance: sourceToken?.balance + balance: sourceToken?.balance, }); const hasInsufficientBalance = useMemo(() => { - if (!sourceAmount || !latestSourceBalance?.atomicBalance || !sourceToken?.decimals) { + if ( + !sourceAmount || + !latestSourceBalance?.atomicBalance || + !sourceToken?.decimals + ) { return false; } - const sourceAmountAtomic = ethers.utils.parseUnits(sourceAmount, sourceToken.decimals); + const sourceAmountAtomic = ethers.utils.parseUnits( + sourceAmount, + sourceToken.decimals, + ); return sourceAmountAtomic.gt(latestSourceBalance.atomicBalance); }, [sourceAmount, latestSourceBalance?.atomicBalance, sourceToken?.decimals]); // Reset bridge state when component unmounts - useEffect(() => () => { - dispatch(resetBridgeState()); - }, [dispatch]); + useEffect( + () => () => { + dispatch(resetBridgeState()); + }, + [dispatch], + ); useEffect(() => { navigation.setOptions(getBridgeNavbar(navigation, route, colors)); @@ -187,24 +200,13 @@ const BridgeView = () => { } }; - // Add function to navigate to slippage modal - const handleSlippagePress = () => { - navigation.navigate(Routes.BRIDGE.MODALS.ROOT, { - screen: Routes.BRIDGE.MODALS.SLIPPAGE_MODAL, - params: { - selectedSlippage: slippage, - onSelectSlippage: setSlippage, - }, - }); - }; - - const handleSourceTokenPress = () => + const handleSourceTokenPress = () => navigation.navigate(Routes.BRIDGE.MODALS.ROOT, { screen: Routes.BRIDGE.MODALS.SOURCE_TOKEN_SELECTOR, params: {}, }); - const handleDestTokenPress = () => + const handleDestTokenPress = () => navigation.navigate(Routes.BRIDGE.MODALS.ROOT, { screen: Routes.BRIDGE.MODALS.DEST_TOKEN_SELECTOR, params: {}, @@ -259,7 +261,9 @@ const BridgeView = () => { token={sourceToken} tokenBalance={latestSourceBalance?.displayBalance} //@ts-expect-error - The utils/network file is still JS and this function expects a networkType, and should be optional - networkImageSource={getNetworkImageSource({ chainId: sourceToken?.chainId as Hex })} + networkImageSource={getNetworkImageSource({ + chainId: sourceToken?.chainId as Hex, + })} autoFocus isReadonly testID="source-token-area" @@ -279,21 +283,22 @@ const BridgeView = () => { + + + -