From 6885c34518262b9a53d7df4c7d52f49c4baeb2f1 Mon Sep 17 00:00:00 2001 From: Pete Watters <2938440+pete-watters@users.noreply.github.com> Date: Tue, 5 Dec 2023 12:10:58 +0000 Subject: [PATCH] chore: replace drawer with dialog, add containers and global header footers, refactor onboarding, ref #4371 --- .storybook/main.ts | 6 + .storybook/preview.ts | 7 + .storybook/viewports.ts | 49 ++++ package.json | 1 + public/html/popup-center.html | 12 - src/app/app.tsx | 28 +-- src/app/common/hooks/use-drawers.ts | 26 --- src/app/common/hooks/use-event-listener.ts | 74 ------ src/app/common/hooks/use-latest-ref.ts | 17 -- src/app/common/hooks/use-media-query.ts | 23 -- src/app/common/hooks/use-route-header.ts | 16 -- src/app/common/utils.ts | 4 - src/app/common/utils/copy-to-clipboard.ts | 6 + src/app/common/utils/use-interval.ts | 26 --- src/app/common/utils/use-waiting-message.ts | 39 ---- .../components/account/account-addresses.tsx | 5 +- src/app/components/app-version.tsx | 27 ++- .../bitcoin-custom-fee/bitcoin-custom-fee.tsx | 12 +- .../broadcast-error-dialog.tsx} | 22 +- .../broadcast-error-drawer.tsx | 17 -- .../components/centered-page-container.tsx | 15 -- .../choose-asset-container.tsx | 4 +- .../crypto-asset-list.layout.tsx | 10 - .../choose-crypto-asset/crypto-asset-list.tsx | 8 +- src/app/components/drawer/base-drawer.tsx | 127 ----------- .../drawer/components/drawer-header.tsx | 56 ----- .../components/drawer/controlled-drawer.tsx | 30 --- .../generic-error/generic-error.tsx | 5 - src/app/components/header.tsx | 86 ------- src/app/components/leather-logo.tsx | 23 -- src/app/components/modal-header.tsx | 86 ------- src/app/components/network-mode-badge.tsx | 33 --- src/app/components/preview-button.tsx | 24 -- src/app/components/request-password.tsx | 128 +++++------ .../components/secret-key/secret-key-grid.tsx | 24 -- .../secret-key/two-column.layout.tsx | 56 ----- src/app/components/status-ready.tsx | 2 +- .../activity-list/components/tab-wrapper.tsx | 3 +- src/app/features/add-network/add-network.tsx | 15 +- src/app/features/asset-list/asset-list.tsx | 2 +- .../bitcoin-choose-fee/bitcoin-choose-fee.tsx | 4 +- .../features/collectibles/collectibles.tsx | 2 +- .../_collectible-types/collectible-other.tsx | 2 +- .../collectible-text.layout.tsx | 2 +- ...ibes.layout.tsx => collectible.layout.tsx} | 16 +- .../features/container/container.layout.tsx | 18 -- src/app/features/container/container.tsx | 153 +++++++++++-- src/app/features/container/total-balance.tsx | 57 +++++ .../container/utils/get-popup-header.ts | 38 ++++ .../container/utils/get-title-from-url.ts | 35 +++ .../features/container/utils/route-helpers.ts | 49 ++++ .../current-account-avatar.tsx | 13 +- .../features/current-account/popup-header.tsx | 69 ------ .../components/edit-nonce-field.tsx | 0 .../components/edit-nonce-form.tsx | 0 .../edit-nonce-dialog/edit-nonce-dialog.tsx} | 28 +-- .../high-fee-dialog/high-fee-dialog.tsx | 74 ++++++ .../components/fee-multiplier-button.tsx | 0 .../components/fee-multiplier.tsx | 0 .../components/increase-btc-fee-form.tsx | 0 .../components/increase-fee-actions.tsx | 0 .../components/increase-fee-field.tsx | 2 +- .../components/increase-stx-fee-form.tsx | 0 .../hooks/use-btc-increase-fee.ts | 0 .../hooks/use-selected-tx.ts | 0 .../increase-btc-fee-dialog.tsx} | 14 +- .../increase-fee-dialog.tsx} | 15 +- .../increase-fee-sent-dialog.tsx} | 13 +- .../increase-stx-fee-dialog.tsx} | 6 +- .../leather-intro-dialog/confetti-config.ts | 0 .../leather-intro-dialog.tsx | 5 - .../leather-intro-steps.tsx | 0 .../components/account-list-unavailable.tsx | 0 .../components/switch-account-list-item.tsx | 3 +- .../components/switch-account-list.tsx | 13 +- .../switch-account-dialog.tsx | 62 +++++ .../features/errors/app-error-boundary.tsx | 4 - .../components/high-fee-confirmation.tsx | 48 ---- .../high-fee-drawer/high-fee-drawer.tsx | 28 --- .../hiro-messages/in-app-messages.tsx | 1 + src/app/features/html-head/head-provider.tsx | 14 +- .../ledger/components/ledger-wrapper.tsx | 2 +- .../jwt-signing/ledger-sign-jwt-container.tsx | 16 +- .../ledger-stacks-sign-msg-container.tsx | 21 +- .../request-keys/request-keys-flow.tsx | 11 +- .../tx-signing/tx-signing-flow.tsx | 21 +- .../connect-ledger-error.layout.tsx | 2 +- .../connect-device/connect-ledger-start.tsx | 6 +- .../unsupported-browser.layout.tsx | 19 +- .../features/message-signer/hash-drawer.tsx | 3 +- .../message-signer/message-preview-box.tsx | 7 +- .../features/psbt-signer/components/index.ts | 9 + .../components/psbt-request-actions.tsx | 30 +-- .../components/psbt-signer.layout.tsx | 19 -- src/app/features/psbt-signer/psbt-signer.tsx | 42 ++-- ...trieve-taproot-to-native-segwit.layout.tsx | 6 +- .../secret-key-displayer.tsx | 8 +- .../components/settings-menu-item.tsx | 27 --- .../components/settings-menu-wrapper.tsx | 27 --- .../settings-dropdown/settings-dropdown.tsx | 170 -------------- .../components/advanced-menu-items.tsx | 27 +-- .../components/ledger-item-row.tsx | 0 .../components/network-list-item.layout.tsx | 8 +- .../settings/network}/network-list-item.tsx | 0 src/app/features/settings/network/network.tsx | 78 +++++++ src/app/features/settings/settings.tsx | 214 ++++++++++++++++++ .../settings/sign-out/sign-out-confirm.tsx | 36 +++ .../features/settings/sign-out/sign-out.tsx | 105 +++++++++ .../theme/theme-dialog.tsx} | 14 +- .../theme/theme-list-item.tsx} | 22 +- .../components/nested-tuple-displayer.tsx | 2 +- .../stacks-message-signing.tsx | 3 - .../hooks/use-stacks-transaction-summary.ts | 1 - .../stacks-transaction-signer.tsx | 17 +- .../submit-action.tsx | 10 +- .../transaction-error/error-messages.tsx | 12 +- .../components/create-account-action.tsx | 25 -- .../switch-account-drawer.tsx | 55 ----- .../features/theme-drawer/theme-drawer.tsx | 18 -- .../features/theme-drawer/theme-list-item.tsx | 25 -- .../bitcoin-contract-list.tsx | 7 +- .../bitcoin-contract-list-item-layout.tsx | 2 +- .../bitcoin-contract-list-layout.tsx | 22 -- .../bitcoin-contract-request.tsx | 8 +- .../bitcoin-contract-request-actions.tsx | 51 ++--- .../bitcoin-contract-request-layout.tsx | 20 -- .../pages/choose-account/choose-account.tsx | 2 - .../choose-account/components/accounts.tsx | 2 +- .../choose-asset-to-fund.tsx | 4 - .../fund/components/fund-account-tile.tsx | 2 +- src/app/pages/fund/components/fund.layout.tsx | 56 ++--- src/app/pages/fund/fiat-providers-list.tsx | 20 +- src/app/pages/fund/fund.tsx | 8 +- .../pages/home/components/account-actions.tsx | 8 +- .../pages/home/components/account-area.tsx | 28 --- .../home/components/account-info-card.tsx | 67 ------ src/app/pages/home/components/home-tabs.tsx | 8 +- src/app/pages/home/components/home.layout.tsx | 31 --- src/app/pages/home/components/send-button.tsx | 7 +- src/app/pages/home/home.tsx | 45 ++-- .../allow-diagnostics-layout.tsx | 84 +++---- .../allow-diagnostics/allow-diagnostics.tsx | 4 - .../back-up-secret-key/back-up-secret-key.tsx | 48 +++- .../components/back-up-secret-key.content.tsx | 41 ---- .../set-password/components/password-bars.tsx | 28 ++- .../onboarding/set-password/set-password.tsx | 64 ++---- .../sign-in/components/sign-in.content.tsx | 26 --- .../onboarding/sign-in/mnemonic-form.tsx | 47 ++-- src/app/pages/onboarding/sign-in/sign-in.tsx | 53 ++--- .../onboarding/welcome/welcome.layout.tsx | 128 ----------- src/app/pages/onboarding/welcome/welcome.tsx | 7 +- .../components/receive-collectibles.tsx | 55 +++++ .../receive/components/receive-items.tsx | 21 -- .../components/receive-tokens.layout.tsx | 28 ++- .../receive/components/receive-tokens.tsx | 44 ++++ src/app/pages/receive/receive-btc.tsx | 16 +- src/app/pages/receive/receive-dialog.tsx | 126 +++++++++++ src/app/pages/receive/receive-modal.tsx | 151 ------------ src/app/pages/receive/receive-ordinal.tsx | 14 +- src/app/pages/receive/receive-stx.tsx | 16 +- .../rpc-send-transfer-confirmation.tsx | 1 - .../rpc-send-transfer-container.tsx | 5 - .../rpc-sign-bip322-message.tsx | 4 - .../pages/rpc-sign-psbt/use-rpc-sign-psbt.tsx | 1 - .../components/add-network-button.tsx | 17 -- .../components/network-list.layout.tsx | 9 - .../components/network-status-indicator.tsx | 10 - .../pages/select-network/select-network.tsx | 67 ------ .../choose-crypto-asset.tsx | 18 +- .../locked-bitcoin-summary.tsx | 4 - .../send-inscription-choose-fee.tsx | 12 +- .../send-inscription-form.tsx | 12 +- .../send-inscription-review.tsx | 12 +- .../sent-inscription-summary.tsx | 11 +- src/app/pages/send/send-container.tsx | 30 --- .../components/form-footer.tsx | 30 --- .../account-list-item.tsx | 2 +- .../recipient-accounts-dialog.tsx} | 31 +-- .../select-account-button.tsx | 0 .../recipient-type-dropdown.tsx | 2 +- .../send-crypto-asset-form.layout.tsx | 26 +-- .../form/brc-20/brc-20-choose-fee.tsx | 9 - .../brc-20/brc20-send-form-confirmation.tsx | 5 - .../form/brc-20/brc20-send-form.tsx | 85 ++++--- .../form/btc/btc-choose-fee.tsx | 6 +- .../form/btc/btc-send-form-confirmation.tsx | 5 - .../form/btc/btc-send-form.tsx | 98 ++++---- .../form/btc/use-btc-choose-fee.tsx | 10 - .../form/stacks/stacks-common-send-form.tsx | 71 ++++-- .../stacks/stacks-send-form-confirmation.tsx | 14 +- .../stacks/use-stacks-common-send-form.tsx | 13 +- .../form/stx/stx-send-form.tsx | 4 + .../form/stx/use-stx-send-form.tsx | 6 +- .../hooks/use-send-form-navigate.ts | 4 - .../send-crypto-asset-form.routes.tsx | 52 +++-- .../send/sent-summary/brc20-sent-summary.tsx | 4 - .../send/sent-summary/btc-sent-summary.tsx | 4 - .../send/sent-summary/stx-sent-summary.tsx | 4 - .../sign-out-confirm.layout.tsx | 115 ---------- .../sign-out-confirm/sign-out-confirm.tsx | 27 --- src/app/pages/swap/alex-swap-container.tsx | 6 +- .../swap/components/swap-container.layout.tsx | 25 -- .../components/swap-asset-list.layout.tsx | 9 - .../components/swap-asset-list.tsx | 7 +- .../swap-choose-asset/swap-choose-asset.tsx | 29 +-- .../pages/swap/swap-review/swap-review.tsx | 4 - src/app/pages/swap/swap.tsx | 4 - .../transaction-request.tsx | 20 +- src/app/pages/unlock.tsx | 41 +--- .../update-profile-request.tsx | 4 - .../components/view-secret-key.content.tsx | 24 -- .../pages/view-secret-key/view-secret-key.tsx | 46 ++-- src/app/routes/app-routes.tsx | 28 +-- src/app/routes/receive-routes.tsx | 6 +- src/app/routes/request-routes.tsx | 8 +- src/app/routes/settings-routes.tsx | 15 -- src/app/store/networks/networks.ts | 2 + src/app/store/settings/settings.selectors.ts | 20 +- src/app/store/settings/settings.slice.ts | 9 - src/app/store/ui/ui.hooks.ts | 30 +-- src/app/store/ui/ui.ts | 11 - .../account-avatar}/account-avatar-item.tsx | 2 +- .../account-avatar}/account-avatar.tsx | 0 .../account/account.card.stories.tsx | 33 +++ .../ui/components/account/account.card.tsx | 66 ++++++ .../components/account}/action-button.tsx | 14 +- .../avatar-icon}/accessible-icon.tsx | 0 .../bullet-separator/bullet-separator.tsx | 2 +- .../ui/components/button/button.stories.tsx | 29 +-- src/app/ui/components/button/button.tsx | 5 +- .../containers/container.layout.tsx | 30 +++ .../containers/dialog/dialog.stories.tsx | 15 ++ .../components/containers/dialog/dialog.tsx | 61 +++++ .../containers/footers}/available-balance.tsx | 18 +- .../containers/footers/footer.stories.tsx | 153 +++++++++++++ .../components/containers/footers/footer.tsx | 32 +++ .../headers/components/network-mode-badge.tsx | 27 +++ .../headers}/header-action-button.tsx | 26 ++- .../containers/headers/header.stories.tsx | 22 ++ .../components/containers/headers/header.tsx | 86 +++++++ .../containers/popup/popup-card.tsx | 21 ++ .../dropdown-menu-item.layout.tsx | 0 .../dropdown-menu.stories.tsx | 0 .../dropdown-menu.tsx | 38 +++- src/app/ui/components/flag/flag.stories.tsx | 4 +- src/app/ui/components/item/item.stories.tsx | 10 +- src/app/ui/components/link/link.stories.tsx | 14 -- src/app/ui/components/link/link.tsx | 2 +- src/app/ui/components/logo.tsx | 20 ++ .../mnemonic-key/mnemonic-word-input.tsx | 0 .../mnemonic-key/utils/error-handling.ts | 0 .../mnemonic-key/utils/validation.ts | 0 .../components/secret-key/secret-key-grid.tsx | 20 ++ .../secret-key}/secret-key-word.tsx | 2 +- .../secret-key/secret-key.layout.tsx} | 47 ++-- src/app/ui/icons/docs/icons.mdx | 4 +- src/app/ui/layout/card/card-content.tsx | 22 ++ src/app/ui/layout/card/card.stories.tsx | 30 +++ src/app/ui/layout/card/card.tsx | 26 +++ .../ui/layout/page/page.layout.stories.tsx | 21 ++ src/app/ui/layout/page/page.layout.tsx | 24 ++ src/app/ui/pages/home.layout.stories.tsx | 51 +++++ src/app/ui/pages/home.layout.tsx | 31 +++ .../ui/pages/two-column.layout.stories.tsx | 20 ++ src/app/ui/pages/two-column.layout.tsx | 60 +++++ src/app/ui/pages/welcome.layout.tsx | 143 ++++++++++++ src/app/ui/utils/prism.tsx | 2 +- src/background/messaging/messaging-utils.ts | 4 +- src/background/popup-center.ts | 41 ---- src/background/popup.ts | 63 ++++++ src/shared/constants.ts | 3 - src/shared/route-urls.ts | 5 +- src/shared/utils/px-string-to-number.spec.ts | 12 + src/shared/utils/px-string-to-number.ts | 3 + test-app/src/components/app.tsx | 19 +- test-app/src/components/bns.tsx | 2 + test-app/src/components/counter-actions.tsx | 30 +-- test-app/src/components/header.tsx | 32 --- tests/page-object-models/home.page.ts | 20 +- tests/page-object-models/onboarding.page.ts | 1 - tests/page-object-models/send.page.ts | 2 +- tests/selectors/home.selectors.ts | 4 +- tests/selectors/onboarding.selectors.ts | 2 +- tests/selectors/settings.selectors.ts | 3 +- tests/selectors/shared-component.selectors.ts | 4 +- ...settings-menu.spec.ts => settings.spec.ts} | 1 + theme/global/full-page-styles.ts | 14 -- theme/global/global.ts | 61 ++++- theme/global/popup-center-styles.ts | 8 - theme/global/popup-styles.ts | 24 -- theme/tokens.ts | 29 +++ webpack/webpack.config.base.js | 5 - 292 files changed, 3535 insertions(+), 3737 deletions(-) create mode 100644 .storybook/viewports.ts delete mode 100644 public/html/popup-center.html delete mode 100644 src/app/common/hooks/use-drawers.ts delete mode 100644 src/app/common/hooks/use-event-listener.ts delete mode 100644 src/app/common/hooks/use-latest-ref.ts delete mode 100644 src/app/common/hooks/use-media-query.ts delete mode 100644 src/app/common/hooks/use-route-header.ts create mode 100644 src/app/common/utils/copy-to-clipboard.ts delete mode 100644 src/app/common/utils/use-interval.ts delete mode 100644 src/app/common/utils/use-waiting-message.ts rename src/app/components/{broadcast-error-drawer/broadcast-error-drawer.layout.tsx => broadcast-error-dialog/broadcast-error-dialog.tsx} (62%) delete mode 100644 src/app/components/broadcast-error-drawer/broadcast-error-drawer.tsx delete mode 100644 src/app/components/centered-page-container.tsx delete mode 100644 src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list.layout.tsx delete mode 100644 src/app/components/drawer/base-drawer.tsx delete mode 100644 src/app/components/drawer/components/drawer-header.tsx delete mode 100644 src/app/components/drawer/controlled-drawer.tsx delete mode 100644 src/app/components/header.tsx delete mode 100644 src/app/components/leather-logo.tsx delete mode 100644 src/app/components/modal-header.tsx delete mode 100644 src/app/components/network-mode-badge.tsx delete mode 100644 src/app/components/preview-button.tsx delete mode 100644 src/app/components/secret-key/secret-key-grid.tsx delete mode 100644 src/app/components/secret-key/two-column.layout.tsx rename src/app/features/collectibles/components/{collectibes.layout.tsx => collectible.layout.tsx} (79%) delete mode 100644 src/app/features/container/container.layout.tsx create mode 100644 src/app/features/container/total-balance.tsx create mode 100644 src/app/features/container/utils/get-popup-header.ts create mode 100644 src/app/features/container/utils/get-title-from-url.ts create mode 100644 src/app/features/container/utils/route-helpers.ts delete mode 100644 src/app/features/current-account/popup-header.tsx rename src/app/features/{edit-nonce-drawer => dialogs/edit-nonce-dialog}/components/edit-nonce-field.tsx (100%) rename src/app/features/{edit-nonce-drawer => dialogs/edit-nonce-dialog}/components/edit-nonce-form.tsx (100%) rename src/app/features/{edit-nonce-drawer/edit-nonce-drawer.tsx => dialogs/edit-nonce-dialog/edit-nonce-dialog.tsx} (76%) create mode 100644 src/app/features/dialogs/high-fee-dialog/high-fee-dialog.tsx rename src/app/features/{increase-fee-drawer => dialogs/increase-fee-dialog}/components/fee-multiplier-button.tsx (100%) rename src/app/features/{increase-fee-drawer => dialogs/increase-fee-dialog}/components/fee-multiplier.tsx (100%) rename src/app/features/{increase-fee-drawer => dialogs/increase-fee-dialog}/components/increase-btc-fee-form.tsx (100%) rename src/app/features/{increase-fee-drawer => dialogs/increase-fee-dialog}/components/increase-fee-actions.tsx (100%) rename src/app/features/{increase-fee-drawer => dialogs/increase-fee-dialog}/components/increase-fee-field.tsx (98%) rename src/app/features/{increase-fee-drawer => dialogs/increase-fee-dialog}/components/increase-stx-fee-form.tsx (100%) rename src/app/features/{increase-fee-drawer => dialogs/increase-fee-dialog}/hooks/use-btc-increase-fee.ts (100%) rename src/app/features/{increase-fee-drawer => dialogs/increase-fee-dialog}/hooks/use-selected-tx.ts (100%) rename src/app/features/{increase-fee-drawer/increase-btc-fee-drawer.tsx => dialogs/increase-fee-dialog/increase-btc-fee-dialog.tsx} (69%) rename src/app/features/{increase-fee-drawer/increase-fee-drawer.tsx => dialogs/increase-fee-dialog/increase-fee-dialog.tsx} (67%) rename src/app/features/{increase-fee-drawer/increase-fee-sent-drawer.tsx => dialogs/increase-fee-dialog/increase-fee-sent-dialog.tsx} (60%) rename src/app/features/{increase-fee-drawer/increase-stx-fee-drawer.tsx => dialogs/increase-fee-dialog/increase-stx-fee-dialog.tsx} (90%) rename src/app/features/{ => dialogs}/leather-intro-dialog/confetti-config.ts (100%) rename src/app/features/{ => dialogs}/leather-intro-dialog/leather-intro-dialog.tsx (90%) rename src/app/features/{ => dialogs}/leather-intro-dialog/leather-intro-steps.tsx (100%) rename src/app/features/{switch-account-drawer => dialogs/switch-account-dialog}/components/account-list-unavailable.tsx (100%) rename src/app/features/{switch-account-drawer => dialogs/switch-account-dialog}/components/switch-account-list-item.tsx (95%) rename src/app/features/{switch-account-drawer => dialogs/switch-account-dialog}/components/switch-account-list.tsx (79%) create mode 100644 src/app/features/dialogs/switch-account-dialog/switch-account-dialog.tsx delete mode 100644 src/app/features/high-fee-drawer/components/high-fee-confirmation.tsx delete mode 100644 src/app/features/high-fee-drawer/high-fee-drawer.tsx create mode 100644 src/app/features/psbt-signer/components/index.ts delete mode 100644 src/app/features/psbt-signer/components/psbt-signer.layout.tsx delete mode 100644 src/app/features/settings-dropdown/components/settings-menu-item.tsx delete mode 100644 src/app/features/settings-dropdown/components/settings-menu-wrapper.tsx delete mode 100644 src/app/features/settings-dropdown/settings-dropdown.tsx rename src/app/features/{settings-dropdown => settings}/components/advanced-menu-items.tsx (77%) rename src/app/features/{settings-dropdown => settings}/components/ledger-item-row.tsx (100%) rename src/app/{pages/select-network => features/settings/network}/components/network-list-item.layout.tsx (88%) rename src/app/{pages/select-network => features/settings/network}/network-list-item.tsx (100%) create mode 100644 src/app/features/settings/network/network.tsx create mode 100644 src/app/features/settings/settings.tsx create mode 100644 src/app/features/settings/sign-out/sign-out-confirm.tsx create mode 100644 src/app/features/settings/sign-out/sign-out.tsx rename src/app/features/{theme-drawer/theme-list.tsx => settings/theme/theme-dialog.tsx} (71%) rename src/app/features/{theme-drawer/theme-list-item-layout.tsx => settings/theme/theme-list-item.tsx} (54%) delete mode 100644 src/app/features/switch-account-drawer/components/create-account-action.tsx delete mode 100644 src/app/features/switch-account-drawer/switch-account-drawer.tsx delete mode 100644 src/app/features/theme-drawer/theme-drawer.tsx delete mode 100644 src/app/features/theme-drawer/theme-list-item.tsx delete mode 100644 src/app/pages/bitcoin-contract-list/components/bitcoin-contract-list-layout.tsx delete mode 100644 src/app/pages/bitcoin-contract-request/components/bitcoin-contract-request-layout.tsx delete mode 100644 src/app/pages/home/components/account-area.tsx delete mode 100644 src/app/pages/home/components/account-info-card.tsx delete mode 100644 src/app/pages/home/components/home.layout.tsx delete mode 100644 src/app/pages/onboarding/back-up-secret-key/components/back-up-secret-key.content.tsx delete mode 100644 src/app/pages/onboarding/sign-in/components/sign-in.content.tsx delete mode 100644 src/app/pages/onboarding/welcome/welcome.layout.tsx create mode 100644 src/app/pages/receive/components/receive-collectibles.tsx delete mode 100644 src/app/pages/receive/components/receive-items.tsx create mode 100644 src/app/pages/receive/components/receive-tokens.tsx create mode 100644 src/app/pages/receive/receive-dialog.tsx delete mode 100644 src/app/pages/receive/receive-modal.tsx delete mode 100644 src/app/pages/select-network/components/add-network-button.tsx delete mode 100644 src/app/pages/select-network/components/network-list.layout.tsx delete mode 100644 src/app/pages/select-network/components/network-status-indicator.tsx delete mode 100644 src/app/pages/select-network/select-network.tsx delete mode 100644 src/app/pages/send/send-container.tsx delete mode 100644 src/app/pages/send/send-crypto-asset-form/components/form-footer.tsx rename src/app/pages/send/send-crypto-asset-form/components/{recipient-accounts-drawer => recipient-accounts-dialog}/account-list-item.tsx (95%) rename src/app/pages/send/send-crypto-asset-form/components/{recipient-accounts-drawer/recipient-accounts-drawer.tsx => recipient-accounts-dialog/recipient-accounts-dialog.tsx} (60%) rename src/app/pages/send/send-crypto-asset-form/components/{recipient-accounts-drawer => recipient-accounts-dialog}/select-account-button.tsx (100%) delete mode 100644 src/app/pages/sign-out-confirm/sign-out-confirm.layout.tsx delete mode 100644 src/app/pages/sign-out-confirm/sign-out-confirm.tsx delete mode 100644 src/app/pages/swap/components/swap-container.layout.tsx delete mode 100644 src/app/pages/swap/swap-choose-asset/components/swap-asset-list.layout.tsx delete mode 100644 src/app/pages/view-secret-key/components/view-secret-key.content.tsx delete mode 100644 src/app/routes/settings-routes.tsx rename src/app/{components/account => ui/components/account/account-avatar}/account-avatar-item.tsx (76%) rename src/app/{components/account => ui/components/account/account-avatar}/account-avatar.tsx (100%) create mode 100644 src/app/ui/components/account/account.card.stories.tsx create mode 100644 src/app/ui/components/account/account.card.tsx rename src/app/{pages/home/components => ui/components/account}/action-button.tsx (63%) rename src/app/{pages/home/components => ui/components/avatar-icon}/accessible-icon.tsx (100%) create mode 100644 src/app/ui/components/containers/container.layout.tsx create mode 100644 src/app/ui/components/containers/dialog/dialog.stories.tsx create mode 100644 src/app/ui/components/containers/dialog/dialog.tsx rename src/app/{components => ui/components/containers/footers}/available-balance.tsx (62%) create mode 100644 src/app/ui/components/containers/footers/footer.stories.tsx create mode 100644 src/app/ui/components/containers/footers/footer.tsx create mode 100644 src/app/ui/components/containers/headers/components/network-mode-badge.tsx rename src/app/{components/drawer/components => ui/components/containers/headers}/header-action-button.tsx (62%) create mode 100644 src/app/ui/components/containers/headers/header.stories.tsx create mode 100644 src/app/ui/components/containers/headers/header.tsx create mode 100644 src/app/ui/components/containers/popup/popup-card.tsx rename src/app/ui/components/{dowpdown-menu => dropdown-menu}/dropdown-menu-item.layout.tsx (100%) rename src/app/ui/components/{dowpdown-menu => dropdown-menu}/dropdown-menu.stories.tsx (100%) rename src/app/ui/components/{dowpdown-menu => dropdown-menu}/dropdown-menu.tsx (73%) create mode 100644 src/app/ui/components/logo.tsx rename src/app/{ => ui}/components/secret-key/mnemonic-key/mnemonic-word-input.tsx (100%) rename src/app/{ => ui}/components/secret-key/mnemonic-key/utils/error-handling.ts (100%) rename src/app/{ => ui}/components/secret-key/mnemonic-key/utils/validation.ts (100%) create mode 100644 src/app/ui/components/secret-key/secret-key-grid.tsx rename src/app/{features/secret-key-displayer/components => ui/components/secret-key}/secret-key-word.tsx (93%) rename src/app/{features/secret-key-displayer/secret-key-displayer.layout.tsx => ui/components/secret-key/secret-key.layout.tsx} (63%) create mode 100644 src/app/ui/layout/card/card-content.tsx create mode 100644 src/app/ui/layout/card/card.stories.tsx create mode 100644 src/app/ui/layout/card/card.tsx create mode 100644 src/app/ui/layout/page/page.layout.stories.tsx create mode 100644 src/app/ui/layout/page/page.layout.tsx create mode 100644 src/app/ui/pages/home.layout.stories.tsx create mode 100644 src/app/ui/pages/home.layout.tsx create mode 100644 src/app/ui/pages/two-column.layout.stories.tsx create mode 100644 src/app/ui/pages/two-column.layout.tsx create mode 100644 src/app/ui/pages/welcome.layout.tsx delete mode 100644 src/background/popup-center.ts create mode 100644 src/background/popup.ts create mode 100644 src/shared/utils/px-string-to-number.spec.ts create mode 100644 src/shared/utils/px-string-to-number.ts delete mode 100644 test-app/src/components/header.tsx rename tests/specs/settings/{settings-menu.spec.ts => settings.spec.ts} (97%) delete mode 100644 theme/global/full-page-styles.ts delete mode 100644 theme/global/popup-center-styles.ts delete mode 100644 theme/global/popup-styles.ts diff --git a/.storybook/main.ts b/.storybook/main.ts index 983884a4ff8..79a6524c05e 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -34,6 +34,12 @@ const config: StorybookConfig = { }, ], }, + + { + test: /\.(ts|tsx)$/, + loader: 'esbuild-loader', + options: { tsconfig: './tsconfig.json', target: 'es2020' }, + }, ], }, }, diff --git a/.storybook/preview.ts b/.storybook/preview.ts index ae4ce4cab9a..fe3b4426509 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -1,6 +1,7 @@ import type { Preview } from '@storybook/react'; import '../src/app/index.css'; +import { customViewports } from './viewports'; const preview: Preview = { parameters: { @@ -24,6 +25,12 @@ const preview: Preview = { date: /Date$/i, }, }, + viewport: { + viewports: { + ...customViewports, + }, + }, + toc: true, }, }; diff --git a/.storybook/viewports.ts b/.storybook/viewports.ts new file mode 100644 index 00000000000..ddfe099aad4 --- /dev/null +++ b/.storybook/viewports.ts @@ -0,0 +1,49 @@ +import { breakpoints } from '@leather-wallet/tokens'; + +// TODO import from '@leather-wallet/tokens' +import { tokens } from '../theme/tokens'; + +export const customViewports = { + popup: { + name: 'Popup', + styles: { + width: tokens.sizes.popupWidth.value, + height: tokens.sizes.popupHeight.value, + }, + }, + sm: { + name: 'sm', + styles: { + width: breakpoints.sm, + height: '100%', + }, + }, + md: { + name: 'md', + styles: { + width: breakpoints.md, + height: '100%', + }, + }, + lg: { + name: 'lg', + styles: { + width: breakpoints.lg, + height: '100%', + }, + }, + xl: { + name: 'xl', + styles: { + width: breakpoints.xl, + height: '100%', + }, + }, + '2xl': { + name: '2xl', + styles: { + width: breakpoints['2xl'], + height: '100%', + }, + }, +}; diff --git a/package.json b/package.json index 97cf8396508..8e08d8bf049 100644 --- a/package.json +++ b/package.json @@ -145,6 +145,7 @@ "@radix-ui/react-tabs": "1.0.4", "@radix-ui/react-tooltip": "1.0.7", "@radix-ui/themes": "2.0.3", + "@radix-ui/react-dialog": "1.0.5", "@reduxjs/toolkit": "1.9.6", "@scure/base": "1.1.3", "@scure/bip32": "1.3.2", diff --git a/public/html/popup-center.html b/public/html/popup-center.html deleted file mode 100644 index 7d23e5be4ba..00000000000 --- a/public/html/popup-center.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - -
- - - diff --git a/src/app/app.tsx b/src/app/app.tsx index ac9526927ad..6cebc420b81 100644 --- a/src/app/app.tsx +++ b/src/app/app.tsx @@ -1,9 +1,8 @@ import { Suspense } from 'react'; +import { Toaster } from 'react-hot-toast'; import { Provider as ReduxProvider } from 'react-redux'; -import { radixBaseCSS } from '@radix-ui/themes/styles.css'; import { QueryClientProvider } from '@tanstack/react-query'; -import { styled } from 'leather-styles/jsx'; import { PersistGate } from 'redux-persist/integration/react'; import { queryClient } from '@app/common/persistence'; @@ -24,19 +23,22 @@ export function App() { } persistor={persistor}> - {/* TODO: this works but investigate importing radixBaseCSS in panda layer config */} - - - }> - - - - {reactQueryDevToolsEnabled && } - - - + + }> + + + + {reactQueryDevToolsEnabled && } + + + ); diff --git a/src/app/common/hooks/use-drawers.ts b/src/app/common/hooks/use-drawers.ts deleted file mode 100644 index d92f2f48f9b..00000000000 --- a/src/app/common/hooks/use-drawers.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { - useShowHighFeeConfirmationState, - useShowSettingsStore, - useShowSwitchAccountsState, - useShowTxSettingsCallback, -} from '@app/store/ui/ui.hooks'; - -export function useDrawers() { - const [isShowingAccounts, setIsShowingSwitchAccountsState] = useShowSwitchAccountsState(); - const [isShowingHighFeeConfirmation, setIsShowingHighFeeConfirmation] = - useShowHighFeeConfirmationState(); - - const [isShowingSettings, setIsShowingSettings] = useShowSettingsStore(); - const [isShowingTxSettingsCallback, setIsShowingTxSettingsCallback] = useShowTxSettingsCallback(); - - return { - isShowingAccounts, - setIsShowingSwitchAccountsState, - isShowingHighFeeConfirmation, - setIsShowingHighFeeConfirmation, - isShowingSettings, - setIsShowingSettings, - isShowingTxSettingsCallback, - setIsShowingTxSettingsCallback, - }; -} diff --git a/src/app/common/hooks/use-event-listener.ts b/src/app/common/hooks/use-event-listener.ts deleted file mode 100644 index b50275a17c4..00000000000 --- a/src/app/common/hooks/use-event-listener.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { useEffect } from 'react'; - -import { useLatestRef } from './use-latest-ref'; - -// eslint-disable-next-line @typescript-eslint/ban-types -type FunctionArguments = T extends (...args: infer R) => any ? R : never; -type AddEventListener = FunctionArguments; - -let _window: Window | undefined = undefined; - -// Note: Accessing "window" in IE11 is somewhat expensive, and calling "typeof window" -// hits a memory leak, whereas aliasing it and calling "typeof _window" does not. -// Caching the window value at the file scope lets us minimize the impact. -try { - _window = window; -} catch (e) { - /* no-op */ -} - -/** - * Helper to get the window object. The helper will make sure to use a cached variable - * of "window", to avoid overhead and memory leaks in IE11. - */ -function getWindow(node?: HTMLElement | null): Window | undefined { - return node?.ownerDocument?.defaultView ?? _window; -} - -/** - * Check if we can use the DOM. Useful for SSR purposes - */ -function checkIsBrowser() { - const _window = getWindow(); - return Boolean( - // eslint-disable-next-line @typescript-eslint/unbound-method, deprecation/deprecation - typeof _window !== 'undefined' && _window.document && _window.document.createElement - ); -} - -const isBrowser = checkIsBrowser(); - -/** - * React hook to manage browser event listeners - * - * @param event the event name - * @param handler the event handler function to execute - * @param element the dom environment to execute against (defaults to `document`) - * @param options the event listener options - */ -export function useEventListener( - event: keyof WindowEventMap, - handler: (event: any) => void, - element: Document | null = isBrowser ? document : null, - options?: AddEventListener[2] -) { - const savedHandler = useLatestRef(handler); - - useEffect(() => { - if (!element) return; - - const listener = (event: any) => { - savedHandler.current(event); - }; - - element.addEventListener(event, listener, options); - - return () => { - element.removeEventListener(event, listener, options); - }; - }, [event, element, options, savedHandler]); - - return () => { - element?.removeEventListener(event, savedHandler.current, options); - }; -} diff --git a/src/app/common/hooks/use-latest-ref.ts b/src/app/common/hooks/use-latest-ref.ts deleted file mode 100644 index aa73b9c1b29..00000000000 --- a/src/app/common/hooks/use-latest-ref.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { useEffect, useRef } from 'react'; - -/** - * React hook to persist any value between renders, - * but keeps it up-to-date if it changes. - * - * @param value the value or function to persist - */ -export function useLatestRef(value: T) { - const ref = useRef(value); - - useEffect(() => { - ref.current = value; - }, [value]); - - return ref; -} diff --git a/src/app/common/hooks/use-media-query.ts b/src/app/common/hooks/use-media-query.ts deleted file mode 100644 index 1d9249726cc..00000000000 --- a/src/app/common/hooks/use-media-query.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { useEffect, useState } from 'react'; - -import { BreakpointToken, token } from 'leather-styles/tokens'; - -function useMediaQuery(query: string) { - const [matches, setMatches] = useState(false); - - useEffect(() => { - const media = window.matchMedia(query); - if (media.matches !== matches) { - setMatches(media.matches); - } - const listener = () => setMatches(media.matches); - window.addEventListener('resize', listener); - return () => window.removeEventListener('resize', listener); - }, [matches, query]); - - return matches; -} - -export function useViewportMinWidth(viewport: BreakpointToken) { - return useMediaQuery(`(min-width: ${token(`breakpoints.${viewport}`)})`); -} diff --git a/src/app/common/hooks/use-route-header.ts b/src/app/common/hooks/use-route-header.ts deleted file mode 100644 index bd89d969d2b..00000000000 --- a/src/app/common/hooks/use-route-header.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { useEffect } from 'react'; -import { useLocation } from 'react-router-dom'; - -import { useRouteHeaderState } from '@app/store/ui/ui.hooks'; - -export function useRouteHeader(header: React.JSX.Element, isParentRoute?: boolean) { - const location = useLocation(); - const [_, setRouteHeader] = useRouteHeaderState(); - useEffect(() => { - if (location.state?.hasHeaderTitle && isParentRoute) { - return; - } - setRouteHeader(header); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [location.pathname]); -} diff --git a/src/app/common/utils.ts b/src/app/common/utils.ts index 8f7e1235e56..405c2982938 100644 --- a/src/app/common/utils.ts +++ b/src/app/common/utils.ts @@ -265,10 +265,6 @@ export function isPopupMode() { return pageMode === 'popup'; } -export function isFullPageMode() { - return pageMode === 'full'; -} - interface WhenStacksChainIdMap { [ChainID.Mainnet]: T; [ChainID.Testnet]: T; diff --git a/src/app/common/utils/copy-to-clipboard.ts b/src/app/common/utils/copy-to-clipboard.ts new file mode 100644 index 00000000000..2ba36a7dc8d --- /dev/null +++ b/src/app/common/utils/copy-to-clipboard.ts @@ -0,0 +1,6 @@ +import toast from 'react-hot-toast'; + +export function copyToClipboard(text: string) { + navigator.clipboard.writeText(text); + toast.success('Copied to clipboard!'); +} diff --git a/src/app/common/utils/use-interval.ts b/src/app/common/utils/use-interval.ts deleted file mode 100644 index 84b9d19f9ab..00000000000 --- a/src/app/common/utils/use-interval.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { useEffect, useRef } from 'react'; - -import { noop } from '@shared/utils'; - -export function useInterval(callback: () => void, delay: number | null) { - const savedCallback = useRef(noop); - - // Remember the latest callback. - useEffect(() => { - if (savedCallback) { - savedCallback.current = callback; - } - }, [callback]); - - // Set up the interval. - useEffect(() => { - function tick() { - savedCallback.current(); - } - if (delay !== null) { - const id = setInterval(tick, delay); - return () => clearInterval(id); - } - return; - }, [delay]); -} diff --git a/src/app/common/utils/use-waiting-message.ts b/src/app/common/utils/use-waiting-message.ts deleted file mode 100644 index 6ac9701c667..00000000000 --- a/src/app/common/utils/use-waiting-message.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { useMemo, useRef, useState } from 'react'; - -import { useInterval } from './use-interval'; - -// Keys are the seconds to wait before showing the message -export type WaitingMessages = Record; - -function messageForSecondsPassed(waitingMessages: WaitingMessages, seconds: number) { - return waitingMessages[seconds as keyof typeof waitingMessages]; -} - -export const useWaitingMessage = ( - waitingMessages: WaitingMessages, - { waitingMessageInterval } = { - waitingMessageInterval: 1000, - } -): [boolean, string, () => void, () => void] => { - const [isRunning, setIsRunning] = useState(false); - const [waitingMessage, setWaitingMessage] = useState(messageForSecondsPassed(waitingMessages, 0)); - const handlers = useMemo( - () => ({ - startWaitingMessage: () => setIsRunning(true), - stopWaitingMessage: () => setIsRunning(false), - }), - [] - ); - const secondsPassed = useRef(0); - - useInterval( - () => { - secondsPassed.current += waitingMessageInterval / 1000; - const newMessage = messageForSecondsPassed(waitingMessages, secondsPassed.current); - if (newMessage) setWaitingMessage(newMessage); - }, - isRunning ? waitingMessageInterval : null - ); - - return [isRunning, waitingMessage, handlers.startWaitingMessage, handlers.stopWaitingMessage]; -}; diff --git a/src/app/components/account/account-addresses.tsx b/src/app/components/account/account-addresses.tsx index f9c3c66b64e..f8feff13b97 100644 --- a/src/app/components/account/account-addresses.tsx +++ b/src/app/components/account/account-addresses.tsx @@ -1,6 +1,5 @@ import { HStack } from 'leather-styles/jsx'; -import { useViewportMinWidth } from '@app/common/hooks/use-media-query'; import { BulletSeparator } from '@app/ui/components/bullet-separator/bullet-separator'; import { Caption } from '@app/ui/components/typography/caption'; import { truncateMiddle } from '@app/ui/utils/truncate-middle'; @@ -12,13 +11,11 @@ interface AccountAddressesProps { index: number; } export function AcccountAddresses({ index }: AccountAddressesProps) { - const isBreakpointSm = useViewportMinWidth('sm'); - return ( - {account => {truncateMiddle(account.address, isBreakpointSm ? 4 : 3)}} + {account => {truncateMiddle(account.address, 4)}} {signer => {truncateMiddle(signer.address, 5)}} diff --git a/src/app/components/app-version.tsx b/src/app/components/app-version.tsx index c67990f8ffe..79acf72111e 100644 --- a/src/app/components/app-version.tsx +++ b/src/app/components/app-version.tsx @@ -1,6 +1,6 @@ import { forwardRef, useMemo } from 'react'; -import { HTMLStyledProps, styled } from 'leather-styles/jsx'; +import { Box, HTMLStyledProps, styled } from 'leather-styles/jsx'; import { BRANCH_NAME, COMMIT_SHA } from '@shared/environment'; @@ -13,19 +13,18 @@ interface AppVersionLabelProps extends HTMLStyledProps<'span'> { } const AppVersionLabel = forwardRef( ({ children, isLatestVersion, ...props }: AppVersionLabelProps, ref) => ( - - {children} - + + + {children} + + ) ); diff --git a/src/app/components/bitcoin-custom-fee/bitcoin-custom-fee.tsx b/src/app/components/bitcoin-custom-fee/bitcoin-custom-fee.tsx index 0913027cca8..2ae4c85bbd0 100644 --- a/src/app/components/bitcoin-custom-fee/bitcoin-custom-fee.tsx +++ b/src/app/components/bitcoin-custom-fee/bitcoin-custom-fee.tsx @@ -1,5 +1,6 @@ import { Dispatch, SetStateAction, useCallback, useRef } from 'react'; +import { SendCryptoAssetSelectors } from '@tests/selectors/send.selectors'; import { Form, Formik, useField } from 'formik'; import { Stack, styled } from 'leather-styles/jsx'; import * as yup from 'yup'; @@ -8,7 +9,7 @@ import { BtcFeeType } from '@shared/models/fees/bitcoin-fees.model'; import { createMoney } from '@shared/models/money.model'; import { openInNewTab } from '@app/common/utils/open-in-new-tab'; -import { PreviewButton } from '@app/components/preview-button'; +import { Button } from '@app/ui/components/button/button'; import { Input } from '@app/ui/components/input/input'; import { Link } from '@app/ui/components/link/link'; @@ -138,7 +139,14 @@ export function BitcoinCustomFee({ /> - + )} diff --git a/src/app/components/broadcast-error-drawer/broadcast-error-drawer.layout.tsx b/src/app/components/broadcast-error-dialog/broadcast-error-dialog.tsx similarity index 62% rename from src/app/components/broadcast-error-drawer/broadcast-error-drawer.layout.tsx rename to src/app/components/broadcast-error-dialog/broadcast-error-dialog.tsx index d6b7de7d14a..a68718d60ca 100644 --- a/src/app/components/broadcast-error-drawer/broadcast-error-drawer.layout.tsx +++ b/src/app/components/broadcast-error-dialog/broadcast-error-dialog.tsx @@ -1,16 +1,19 @@ +import { useLocation, useNavigate } from 'react-router-dom'; + import GenericError from '@assets/images/generic-error.png'; import { Flex, styled } from 'leather-styles/jsx'; +import get from 'lodash.get'; -import { BaseDrawer } from '@app/components/drawer/base-drawer'; import { Button } from '@app/ui/components/button/button'; +import { Dialog } from '@app/ui/components/containers/dialog/dialog'; + +export function BroadcastErrorDialog() { + const navigate = useNavigate(); + const location = useLocation(); + const message = get(location.state, 'message', ''); -interface BroadcastErrorDrawerLayoutProps { - message: string; - onClose(): void; -} -export function BroadcastErrorDrawerLayout({ message, onClose }: BroadcastErrorDrawerLayoutProps) { return ( - } isShowing onClose={onClose} textAlign="center"> + navigate('..')}> @@ -27,10 +31,10 @@ export function BroadcastErrorDrawerLayout({ message, onClose }: BroadcastErrorD Your transaction failed to broadcast{' '} {message && <>because of the error: {message.toLowerCase()}} - - + ); } diff --git a/src/app/components/broadcast-error-drawer/broadcast-error-drawer.tsx b/src/app/components/broadcast-error-drawer/broadcast-error-drawer.tsx deleted file mode 100644 index 576ab38bec8..00000000000 --- a/src/app/components/broadcast-error-drawer/broadcast-error-drawer.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { useLocation, useNavigate } from 'react-router-dom'; - -import get from 'lodash.get'; - -import { BroadcastErrorDrawerLayout } from './broadcast-error-drawer.layout'; - -export function BroadcastErrorDrawer() { - const navigate = useNavigate(); - const location = useLocation(); - - return ( - navigate('..')} - /> - ); -} diff --git a/src/app/components/centered-page-container.tsx b/src/app/components/centered-page-container.tsx deleted file mode 100644 index fc1d1c41d95..00000000000 --- a/src/app/components/centered-page-container.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { Flex, FlexProps } from 'leather-styles/jsx'; - -export function CenteredPageContainer(props: FlexProps) { - return ( - - ); -} diff --git a/src/app/components/crypto-assets/choose-crypto-asset/choose-asset-container.tsx b/src/app/components/crypto-assets/choose-crypto-asset/choose-asset-container.tsx index f2f213c8424..5eae0646903 100644 --- a/src/app/components/crypto-assets/choose-crypto-asset/choose-asset-container.tsx +++ b/src/app/components/crypto-assets/choose-crypto-asset/choose-asset-container.tsx @@ -9,8 +9,8 @@ export function ChooseAssetContainer({ children }: HasChildren) { {children} diff --git a/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list.layout.tsx b/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list.layout.tsx deleted file mode 100644 index c5c9418347b..00000000000 --- a/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list.layout.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { CryptoAssetSelectors } from '@tests/selectors/crypto-asset.selectors'; -import { Stack, StackProps } from 'leather-styles/jsx'; - -export function CryptoAssetListLayout({ children }: StackProps) { - return ( - - {children} - - ); -} diff --git a/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list.tsx b/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list.tsx index b9db5559af2..75ac025b8d2 100644 --- a/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list.tsx +++ b/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list.tsx @@ -1,3 +1,6 @@ +import { CryptoAssetSelectors } from '@tests/selectors/crypto-asset.selectors'; +import { Stack } from 'leather-styles/jsx'; + import type { AllTransferableCryptoAssetBalances } from '@shared/models/crypto-asset-balance.model'; import { StacksFungibleTokenAsset } from '@shared/models/crypto-asset.model'; @@ -10,7 +13,6 @@ import { BtcAvatarIcon } from '@app/ui/components/avatar/btc-avatar-icon'; import { CryptoCurrencyAssetItemLayout } from '../crypto-currency-asset/crypto-currency-asset-item.layout'; import { CryptoAssetListItem } from './crypto-asset-list-item'; -import { CryptoAssetListLayout } from './crypto-asset-list.layout'; interface CryptoAssetListProps { cryptoAssetBalances: AllTransferableCryptoAssetBalances[]; @@ -20,7 +22,7 @@ export function CryptoAssetList({ cryptoAssetBalances, onItemClick }: CryptoAsse const { whenWallet } = useWalletType(); return ( - + {signer => ( @@ -56,6 +58,6 @@ export function CryptoAssetList({ cryptoAssetBalances, onItemClick }: CryptoAsse ), ledger: null, })} - + ); } diff --git a/src/app/components/drawer/base-drawer.tsx b/src/app/components/drawer/base-drawer.tsx deleted file mode 100644 index 0f393401cb3..00000000000 --- a/src/app/components/drawer/base-drawer.tsx +++ /dev/null @@ -1,127 +0,0 @@ -import { ReactNode, Suspense, memo, useCallback, useRef } from 'react'; -import { useNavigate } from 'react-router-dom'; - -import { Box, Flex, FlexProps } from 'leather-styles/jsx'; - -import { noop } from '@shared/utils'; - -import { useEventListener } from '@app/common/hooks/use-event-listener'; -import { useOnClickOutside } from '@app/common/hooks/use-onclickoutside'; - -import { DrawerHeader } from './components/drawer-header'; - -function useDrawer(isShowing: boolean, onClose: () => void, pause?: boolean) { - const ref = useRef(null); - - const handleKeyDown = useCallback( - (e: React.KeyboardEvent) => { - if (isShowing && e.key === 'Escape') { - onClose(); - } - }, - [onClose, isShowing] - ); - - useOnClickOutside(ref, !pause && isShowing ? onClose : null); - useEventListener('keydown', handleKeyDown); - - return ref; -} - -interface BaseDrawerProps extends Omit { - children?: ReactNode; - enableGoBack?: boolean; - icon?: React.JSX.Element; - isShowing: boolean; - isWaitingOnPerformedAction?: boolean; - onClose?(): void; - pauseOnClickOutside?: boolean; - title?: string; - waitingOnPerformedActionMessage?: string; -} -export const BaseDrawer = memo((props: BaseDrawerProps) => { - const { - children, - enableGoBack, - icon, - isShowing, - isWaitingOnPerformedAction, - onClose, - pauseOnClickOutside, - title, - waitingOnPerformedActionMessage, - ...rest - } = props; - const ref = useDrawer(isShowing, onClose ? onClose : noop, pauseOnClickOutside); - const navigate = useNavigate(); - - const onGoBack = () => navigate(-1); - - return ( - - - - - - }>{children} - - - - - ); -}); diff --git a/src/app/components/drawer/components/drawer-header.tsx b/src/app/components/drawer/components/drawer-header.tsx deleted file mode 100644 index c0faa9e2e2c..00000000000 --- a/src/app/components/drawer/components/drawer-header.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { Box, Flex, styled } from 'leather-styles/jsx'; -import { useHover } from 'use-events'; - -import { ArrowLeftIcon } from '@app/ui/icons/arrow-left-icon'; -import { CloseIcon } from '@app/ui/icons/close-icon'; - -import { HeaderActionButton } from './header-action-button'; - -interface DrawerHeaderProps { - enableGoBack?: boolean; - icon?: React.JSX.Element; - isWaitingOnPerformedAction?: boolean; - onClose?(): void; - onGoBack(): void; - title?: string; - waitingOnPerformedActionMessage?: string; -} -export function DrawerHeader({ - enableGoBack, - icon, - isWaitingOnPerformedAction, - onClose, - onGoBack, - title, - waitingOnPerformedActionMessage, -}: DrawerHeaderProps) { - const [isHovered, bind] = useHover(); - - return ( - - {enableGoBack ? ( - } - isWaitingOnPerformedAction={isWaitingOnPerformedAction} - onAction={onGoBack} - /> - ) : ( - - )} - {icon && icon} - {title && {title}} - {isHovered && isWaitingOnPerformedAction && ( - - {waitingOnPerformedActionMessage} - - )} - {onClose && ( - } - isWaitingOnPerformedAction={isWaitingOnPerformedAction} - onAction={onClose} - /> - )} - - ); -} diff --git a/src/app/components/drawer/controlled-drawer.tsx b/src/app/components/drawer/controlled-drawer.tsx deleted file mode 100644 index 02819286cbe..00000000000 --- a/src/app/components/drawer/controlled-drawer.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { ReactNode } from 'react'; - -import { BaseDrawer } from './base-drawer'; - -interface ControlledDrawerProps { - children?: ReactNode; - enableGoBack?: boolean; - icon?: React.JSX.Element; - isShowing: boolean; - onClose(): void; - pauseOnClickOutside?: boolean; - title?: string; -} -// The visibility of this drawer is controlled by an atom -export function ControlledDrawer(props: ControlledDrawerProps) { - const { children, enableGoBack, icon, isShowing, onClose, pauseOnClickOutside, title } = props; - - return ( - - {children} - - ); -} diff --git a/src/app/components/generic-error/generic-error.tsx b/src/app/components/generic-error/generic-error.tsx index 6c4e401f977..757458e2b39 100644 --- a/src/app/components/generic-error/generic-error.tsx +++ b/src/app/components/generic-error/generic-error.tsx @@ -4,9 +4,6 @@ import { FlexProps, styled } from 'leather-styles/jsx'; import { closeWindow } from '@shared/utils'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; -import { Header } from '@app/components/header'; - import { GenericErrorLayout } from './generic-error.layout'; export function GenericErrorListItem({ text }: { text: ReactNode }) { @@ -23,8 +20,6 @@ interface GenericErrorProps extends FlexProps { export function GenericError(props: GenericErrorProps) { const { body, helpTextList, onClose = () => closeWindow(), title, ...rest } = props; - useRouteHeader(
); - return ( - {onClose ? ( - - - - ) : null} - {!title && (!onClose || isBreakpointSm) ? ( - - - navigate(RouteUrls.Home)} - /> - - - - ) : ( - - {title} - - )} - - - {!hideActions && ( - - )} - {actionButton ? actionButton : null} - - - ); -} diff --git a/src/app/components/leather-logo.tsx b/src/app/components/leather-logo.tsx deleted file mode 100644 index 8ec8f24dc8c..00000000000 --- a/src/app/components/leather-logo.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { memo } from 'react'; - -import { styled } from 'leather-styles/jsx'; - -import { LogomarkIcon } from '@app/ui/icons/logomark-icon'; - -interface LeatherLogoProps { - onClick?(): void; -} -export const LeatherLogo = memo((props: LeatherLogoProps) => { - const { onClick } = props; - - return ( - - - - ); -}); diff --git a/src/app/components/modal-header.tsx b/src/app/components/modal-header.tsx deleted file mode 100644 index b1d086e90ce..00000000000 --- a/src/app/components/modal-header.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { useNavigate } from 'react-router-dom'; - -import { SharedComponentsSelectors } from '@tests/selectors/shared-component.selectors'; -import { Box, Flex, styled } from 'leather-styles/jsx'; -import { token } from 'leather-styles/tokens'; - -import { RouteUrls } from '@shared/route-urls'; - -import { NetworkModeBadge } from '@app/components/network-mode-badge'; -import { Button } from '@app/ui/components/button/button'; -import { ArrowLeftIcon } from '@app/ui/icons/arrow-left-icon'; -import { CloseIcon } from '@app/ui/icons/close-icon'; - -interface ModalHeaderProps { - actionButton?: React.JSX.Element; - closeIcon?: boolean; - hideActions?: boolean; - onClose?(): void; - onGoBack?(): void; - defaultClose?: boolean; - defaultGoBack?: boolean; - title: string; -} - -export function ModalHeader({ - actionButton, - hideActions, - onClose, - onGoBack, - closeIcon, - title, - defaultGoBack, - defaultClose, - ...rest -}: ModalHeaderProps) { - const navigate = useNavigate(); - - function defaultCloseAction() { - navigate(RouteUrls.Home); - } - function defaultGoBackAction() { - navigate(-1); - } - - const hasCloseIcon = onClose || defaultClose; - - return ( - - {onGoBack || defaultGoBack ? ( - - - - ) : ( - - )} - - - - {title} - - - - - - {hasCloseIcon && ( - - )} - - - ); -} diff --git a/src/app/components/network-mode-badge.tsx b/src/app/components/network-mode-badge.tsx deleted file mode 100644 index d8067de7392..00000000000 --- a/src/app/components/network-mode-badge.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { memo, useMemo } from 'react'; -import { useNavigate } from 'react-router-dom'; - -import { ChainID } from '@stacks/transactions'; -import { Flex, FlexProps } from 'leather-styles/jsx'; - -import { RouteUrls } from '@shared/route-urls'; - -import { useCurrentNetworkState } from '@app/store/networks/networks.hooks'; -import { Tag } from '@app/ui/components/tag/tag'; - -export const NetworkModeBadge = memo((props: FlexProps) => { - const navigate = useNavigate(); - const { chain, name } = useCurrentNetworkState(); - const isTestnetChain = useMemo( - () => chain.stacks.chainId === ChainID.Testnet, - [chain.stacks.chainId] - ); - - if (!isTestnetChain) return null; - - return ( - navigate(RouteUrls.SelectNetwork, { relative: 'path' })} - position="relative" - zIndex={999} - {...props} - > - - - ); -}); diff --git a/src/app/components/preview-button.tsx b/src/app/components/preview-button.tsx deleted file mode 100644 index cf624992db5..00000000000 --- a/src/app/components/preview-button.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { SendCryptoAssetSelectors } from '@tests/selectors/send.selectors'; -import { useFormikContext } from 'formik'; - -import { Button } from '@app/ui/components/button/button'; - -interface PreviewButtonProps { - text?: string; - isDisabled?: boolean; -} -export function PreviewButton({ text = 'Continue', isDisabled, ...props }: PreviewButtonProps) { - const { handleSubmit } = useFormikContext(); - - return ( - - ); -} diff --git a/src/app/components/request-password.tsx b/src/app/components/request-password.tsx index 1e87f6c88b1..69242b638fe 100644 --- a/src/app/components/request-password.tsx +++ b/src/app/components/request-password.tsx @@ -1,40 +1,30 @@ -import { FormEvent, ReactNode, useCallback, useState } from 'react'; +import { FormEvent, useCallback, useState } from 'react'; import { SettingsSelectors } from '@tests/selectors/settings.selectors'; -import { Stack, styled } from 'leather-styles/jsx'; +import { Box, styled } from 'leather-styles/jsx'; import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; import { useKeyActions } from '@app/common/hooks/use-key-actions'; import { buildEnterKeyEvent } from '@app/common/hooks/use-modifier-key'; -import { WaitingMessages, useWaitingMessage } from '@app/common/utils/use-waiting-message'; import { Button } from '@app/ui/components/button/button'; +import { Footer } from '@app/ui/components/containers/footers/footer'; +import { Logo } from '@app/ui/components/logo'; +import { Card } from '@app/ui/layout/card/card'; +import { Page } from '@app/ui/layout/page/page.layout'; import { ErrorLabel } from './error-label'; -import { TwoColumnLayout } from './secret-key/two-column.layout'; - -const waitingMessages: WaitingMessages = { - '2': 'Verifying password…', - '10': 'Still working…', - '20': 'Almost there', -}; interface RequestPasswordProps { onSuccess(): void; - title?: ReactNode; - caption?: string; } -export function RequestPassword({ title, caption, onSuccess }: RequestPasswordProps) { +export function RequestPassword({ onSuccess }: RequestPasswordProps) { const [password, setPassword] = useState(''); const [error, setError] = useState(''); const { unlockWallet } = useKeyActions(); const analytics = useAnalytics(); - const [isRunning, waitingMessage, startWaitingMessage, stopWaitingMessage] = - useWaitingMessage(waitingMessages); - const submit = useCallback(async () => { const startUnlockTimeMs = performance.now(); void analytics.track('start_unlock'); - startWaitingMessage(); setError(''); try { await unlockWallet(password); @@ -42,80 +32,66 @@ export function RequestPassword({ title, caption, onSuccess }: RequestPasswordPr } catch (error) { setError('The password you entered is invalid'); } - stopWaitingMessage(); const unlockSuccessTimeMs = performance.now(); void analytics.track('complete_unlock', { durationMs: unlockSuccessTimeMs - startUnlockTimeMs, }); - }, [analytics, startWaitingMessage, stopWaitingMessage, unlockWallet, password, onSuccess]); + }, [analytics, unlockWallet, password, onSuccess]); return ( - <> - + - - {title} - - - {(isRunning && waitingMessage) || caption} - + + + + Enter your password } - rightColumn={ - <> - - Your password - - - ) => { - setError(''); - setPassword(e.currentTarget.value); - }} - onKeyUp={buildEnterKeyEvent(submit)} - p="space.04" - placeholder="Enter your password" - ring="none" - type="password" - textStyle="body.02" - value={password} - width="100%" - /> - {error && {error}} - + text="Your password is used to secure your Secret Key and is only used locally on your device." + action={ +
- +
} - /> - + > + ) => { + setError(''); + setPassword(e.currentTarget.value); + }} + onKeyUp={buildEnterKeyEvent(submit)} + p="space.04" + placeholder="Enter your password" + ring="none" + type="password" + textStyle="body.02" + value={password} + width="100%" + /> + {error && {error}} + + {/* TODO: #4735 implement forgot password flow */} + {/* + Forgot password? + */} +
+ ); } diff --git a/src/app/components/secret-key/secret-key-grid.tsx b/src/app/components/secret-key/secret-key-grid.tsx deleted file mode 100644 index c791d7acd1c..00000000000 --- a/src/app/components/secret-key/secret-key-grid.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { Grid, Stack } from 'leather-styles/jsx'; - -interface SecretKeyGridProps { - children: React.ReactNode; -} -export function SecretKeyGrid({ children }: SecretKeyGridProps) { - return ( - - - {children} - - - ); -} diff --git a/src/app/components/secret-key/two-column.layout.tsx b/src/app/components/secret-key/two-column.layout.tsx deleted file mode 100644 index 7ea7e48e29e..00000000000 --- a/src/app/components/secret-key/two-column.layout.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { Flex, Stack, styled } from 'leather-styles/jsx'; - -interface TwoColumnLayoutProps { - leftColumn: React.JSX.Element; - rightColumn: React.JSX.Element; -} - -export function TwoColumnLayout({ - leftColumn, - rightColumn, -}: TwoColumnLayoutProps): React.JSX.Element { - return ( - - - - {leftColumn} - - - - - - {rightColumn} - - - - ); -} diff --git a/src/app/components/status-ready.tsx b/src/app/components/status-ready.tsx index 1b28e08a11c..d0aabde4d7d 100644 --- a/src/app/components/status-ready.tsx +++ b/src/app/components/status-ready.tsx @@ -5,7 +5,7 @@ export function StatusReady() { width: '8px', height: '8px', borderRadius: '50%', - backgroundColor: '#23A978', + background: '#23A978', }} /> ); diff --git a/src/app/features/activity-list/components/tab-wrapper.tsx b/src/app/features/activity-list/components/tab-wrapper.tsx index 7d82c501831..f6b5220731b 100644 --- a/src/app/features/activity-list/components/tab-wrapper.tsx +++ b/src/app/features/activity-list/components/tab-wrapper.tsx @@ -10,8 +10,7 @@ export function ActivityListTabWrapper({ padContent = false, }: ActivityListTabWrapperProps) { return ( - // Height set based on the height of the empty assets screen - + {children} ); diff --git a/src/app/features/add-network/add-network.tsx b/src/app/features/add-network/add-network.tsx index deba150e828..60cedfe0874 100644 --- a/src/app/features/add-network/add-network.tsx +++ b/src/app/features/add-network/add-network.tsx @@ -12,11 +12,8 @@ import { BitcoinNetworkModes, DefaultNetworkConfigurations } from '@shared/const import { RouteUrls } from '@shared/route-urls'; import { isValidUrl } from '@shared/utils/validate-url'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; import { removeTrailingSlash } from '@app/common/url-join'; -import { CenteredPageContainer } from '@app/components/centered-page-container'; import { ErrorLabel } from '@app/components/error-label'; -import { Header } from '@app/components/header'; import { useCurrentStacksNetworkState, useNetworksActions, @@ -24,6 +21,7 @@ import { import { Button } from '@app/ui/components/button/button'; import { Input } from '@app/ui/components/input/input'; import { Title } from '@app/ui/components/typography/title'; +import { Page } from '@app/ui/layout/page/page.layout'; /** * The **peer** network ID. @@ -62,8 +60,6 @@ export function AddNetwork() { const { setFieldValue } = formikProps; - useRouteHeader(
navigate(RouteUrls.Home)} />); - const handleApiChange = (newValue: BitcoinNetworkModes) => { setBitcoinApi(newValue); }; @@ -104,7 +100,7 @@ export function AddNetwork() { }, [bitcoinApi, setStacksUrl, setBitcoinUrl]); return ( - + { @@ -205,9 +201,10 @@ export function AddNetwork() {
Use this form to add a new instance of the{' '} @@ -272,7 +269,7 @@ export function AddNetwork() { Name )} - + ); } diff --git a/src/app/features/asset-list/asset-list.tsx b/src/app/features/asset-list/asset-list.tsx index f8e05c26abe..f1731bd35c3 100644 --- a/src/app/features/asset-list/asset-list.tsx +++ b/src/app/features/asset-list/asset-list.tsx @@ -31,7 +31,7 @@ export function AssetsList() { const { whenWallet } = useWalletType(); return ( - + {whenWallet({ software: ( - + diff --git a/src/app/features/collectibles/collectibles.tsx b/src/app/features/collectibles/collectibles.tsx index 7f440757a5b..2cb61a05127 100644 --- a/src/app/features/collectibles/collectibles.tsx +++ b/src/app/features/collectibles/collectibles.tsx @@ -13,7 +13,7 @@ import { useConfigNftMetadataEnabled } from '@app/query/common/remote-config/rem import { AddCollectible } from './components/add-collectible'; import { Ordinals } from './components/bitcoin/ordinals'; import { Stamps } from './components/bitcoin/stamps'; -import { CollectiblesLayout } from './components/collectibes.layout'; +import { CollectiblesLayout } from './components/collectible.layout'; import { StacksCryptoAssets } from './components/stacks/stacks-crypto-assets'; import { TaprootBalanceDisplayer } from './components/taproot-balance-displayer'; import { useIsFetchingCollectiblesRelatedQuery } from './hooks/use-is-fetching-collectibles'; diff --git a/src/app/features/collectibles/components/_collectible-types/collectible-other.tsx b/src/app/features/collectibles/components/_collectible-types/collectible-other.tsx index 0f6117e9226..cd649dbb4e0 100644 --- a/src/app/features/collectibles/components/_collectible-types/collectible-other.tsx +++ b/src/app/features/collectibles/components/_collectible-types/collectible-other.tsx @@ -10,7 +10,7 @@ export function CollectibleOther({ children, ...props }: CollectibleOtherProps) - + - {title} + + {title} + {isLoading ? ( ) : ( @@ -35,12 +37,10 @@ export function CollectiblesLayout({ {subHeader} {children} diff --git a/src/app/features/container/container.layout.tsx b/src/app/features/container/container.layout.tsx deleted file mode 100644 index a3c5e99e9b8..00000000000 --- a/src/app/features/container/container.layout.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { Flex } from 'leather-styles/jsx'; - -interface ContainerLayoutProps { - children: React.JSX.Element | React.JSX.Element[]; - header: React.JSX.Element | null; -} -export function ContainerLayout(props: ContainerLayoutProps) { - const { children, header } = props; - - return ( - - {header || null} - - {children} - - - ); -} diff --git a/src/app/features/container/container.tsx b/src/app/features/container/container.tsx index 55d4ea9e5c8..151c67e60f3 100644 --- a/src/app/features/container/container.tsx +++ b/src/app/features/container/container.tsx @@ -1,26 +1,59 @@ -import { useEffect } from 'react'; -import { Toaster } from 'react-hot-toast'; -import { Outlet, useLocation } from 'react-router-dom'; +import { useEffect, useState } from 'react'; +import { Outlet, useLocation, useNavigate } from 'react-router-dom'; +import { ChainID } from '@stacks/transactions'; +import { OnboardingSelectors } from '@tests/selectors/onboarding.selectors'; +import { SettingsSelectors } from '@tests/selectors/settings.selectors'; +import { Box } from 'leather-styles/jsx'; +import { token } from 'leather-styles/tokens'; + +import { RouteUrls } from '@shared/route-urls'; import { closeWindow } from '@shared/utils'; import { useAnalytics, useInitalizeAnalytics } from '@app/common/hooks/analytics/use-analytics'; import { LoadingSpinner } from '@app/components/loading-spinner'; +import { CurrentAccountAvatar } from '@app/features/current-account/current-account-avatar'; +import { CurrentAccountName } from '@app/features/current-account/current-account-name'; +import { SwitchAccountDialog } from '@app/features/dialogs/switch-account-dialog/switch-account-dialog'; +import { InAppMessages } from '@app/features/hiro-messages/in-app-messages'; import { useOnSignOut } from '@app/routes/hooks/use-on-sign-out'; import { useOnWalletLock } from '@app/routes/hooks/use-on-wallet-lock'; import { useHasStateRehydrated } from '@app/store'; -import { useRouteHeaderState } from '@app/store/ui/ui.hooks'; +import { useCurrentNetworkState } from '@app/store/networks/networks.hooks'; +import { ContainerLayout } from '@app/ui/components/containers/container.layout'; +import { NetworkModeBadge } from '@app/ui/components/containers/headers/components/network-mode-badge'; +import { Header } from '@app/ui/components/containers/headers/header'; +import { Flag } from '@app/ui/components/flag/flag'; +import { Logo } from '@app/ui/components/logo'; +import { HamburgerIcon } from '@app/ui/icons/'; import { useRestoreFormState } from '../popup-send-form-restoration/use-restore-form-state'; -import { SettingsDropdown } from '../settings-dropdown/settings-dropdown'; -import { SwitchAccountDrawer } from '../switch-account-drawer/switch-account-drawer'; -import { ContainerLayout } from './container.layout'; +import { Settings } from '../settings/settings'; +import { TotalBalance } from './total-balance'; +import { + getDisplayAddresssBalanceOf, + isKnownPopupRoute, + showAccountInfo, +} from './utils/get-popup-header'; +import { getTitleFromUrl } from './utils/get-title-from-url'; +import { + canGoBack, + getIsSessionLocked, + getPageVariant, + hideLogo, + isGetAddressesPopup, + isLandingPage, +} from './utils/route-helpers'; export function Container() { - const [routeHeader] = useRouteHeaderState(); - const { pathname } = useLocation(); + const [isShowingSwitchAccount, setIsShowingSwitchAccount] = useState(false); + const navigate = useNavigate(); + const { pathname: locationPathname } = useLocation(); + const pathname = locationPathname as RouteUrls; + const analytics = useAnalytics(); const hasStateRehydrated = useHasStateRehydrated(); + const { chain, name: chainName } = useCurrentNetworkState(); useOnWalletLock(() => closeWindow()); useOnSignOut(() => closeWindow()); @@ -29,14 +62,108 @@ export function Container() { useEffect(() => void analytics.page('view', `${pathname}`), [analytics, pathname]); + const variant = getPageVariant(pathname); + + useEffect(() => { + // set the whole body colour based on page variant so it can update dynamically + // TODO replace this with data-attributes to improve and fix modal BG colours + if (variant === 'home') { + document.body.style.backgroundColor = token('colors.ink.background-primary'); + } + if (variant === 'page' || variant === 'onboarding') { + document.body.style.backgroundColor = token('colors.ink.background-secondary'); + } + }, [variant, pathname]); + + const displayHeader = !isLandingPage(pathname) && !isGetAddressesPopup(pathname); + const isSessionLocked = getIsSessionLocked(pathname); + + function getOnGoBackLocation(pathname: RouteUrls) { + if (pathname === RouteUrls.Swap || pathname === RouteUrls.Fund) { + return navigate(RouteUrls.Home); + } + return navigate(-1); + } + if (!hasStateRehydrated) return ; return ( <> - - - - + setIsShowingSwitchAccount(false)} + /> + + + getOnGoBackLocation(pathname) : undefined} + settingsMenu={ + isKnownPopupRoute(pathname) ? null : ( + + } + toggleSwitchAccount={() => setIsShowingSwitchAccount(!isShowingSwitchAccount)} + /> + ) + } + networkBadge={ + + } + title={getTitleFromUrl(pathname)} + logo={ + !hideLogo(pathname) && ( + + navigate(RouteUrls.Home) : undefined} + /> + + ) + } + account={ + showAccountInfo(pathname) && ( + + setIsShowingSwitchAccount(!isShowingSwitchAccount) + } + /> + } + > + + + ) + } + totalBalance={ + showAccountInfo(pathname) && ( + + ) + } + /> + ) : null + } + variant={variant} + > diff --git a/src/app/features/container/total-balance.tsx b/src/app/features/container/total-balance.tsx new file mode 100644 index 00000000000..13095a54fd2 --- /dev/null +++ b/src/app/features/container/total-balance.tsx @@ -0,0 +1,57 @@ +import { Suspense } from 'react'; + +import { Box, HStack } from 'leather-styles/jsx'; + +import { BtcBalance } from '@app/components/balance-btc'; +import { StxBalance } from '@app/components/balance-stx'; +import { LoadingRectangle } from '@app/components/loading-rectangle'; +import { useConfigBitcoinEnabled } from '@app/query/common/remote-config/remote-config.query'; +import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; + +interface TotalBalanceLayoutProps { + children: React.ReactNode; +} +function TotalBalanceLayout({ children }: TotalBalanceLayoutProps) { + return ( + + {children} + + ); +} + +interface TotalBalanceProps { + displayAddresssBalanceOf?: 'all' | 'stx'; +} + +/** + * #4370 This code has been ported from legacy PopupHeader to load balances + */ + +function TotalBalanceSuspense({ displayAddresssBalanceOf }: TotalBalanceProps) { + const account = useCurrentStacksAccount(); + const isBitcoinEnabled = useConfigBitcoinEnabled(); + return ( + + + {account && displayAddresssBalanceOf === 'stx' && } + {isBitcoinEnabled && displayAddresssBalanceOf === 'all' && } + + + ); +} + +function TotalBalanceFallback() { + return ( + + + + ); +} + +export function TotalBalance(props: TotalBalanceProps) { + return ( + }> + + + ); +} diff --git a/src/app/features/container/utils/get-popup-header.ts b/src/app/features/container/utils/get-popup-header.ts new file mode 100644 index 00000000000..d24ea0ac2e4 --- /dev/null +++ b/src/app/features/container/utils/get-popup-header.ts @@ -0,0 +1,38 @@ +/** + * POPUP header logic notes here -> https://github.com/leather-wallet/extension/issues/4371#issuecomment-1919114939 + */ +import { RouteUrls } from '@shared/route-urls'; + +export function showAccountInfo(pathname: RouteUrls) { + return ( + pathname === RouteUrls.TransactionRequest || + pathname === RouteUrls.ProfileUpdateRequest || + pathname === RouteUrls.PsbtRequest + ); +} +export function getDisplayAddresssBalanceOf(pathname: RouteUrls) { + switch (pathname) { + case RouteUrls.TransactionRequest: + case RouteUrls.ProfileUpdateRequest: + case RouteUrls.PsbtRequest: + return 'all'; + case RouteUrls.SignatureRequest: + case RouteUrls.RpcGetAddresses: + return undefined; + default: + return 'stx'; + } +} + +export function isKnownPopupRoute(pathname: RouteUrls) { + switch (pathname) { + case RouteUrls.TransactionRequest: + case RouteUrls.ProfileUpdateRequest: + case RouteUrls.PsbtRequest: + case RouteUrls.SignatureRequest: + case RouteUrls.RpcGetAddresses: + return true; + default: + return false; + } +} diff --git a/src/app/features/container/utils/get-title-from-url.ts b/src/app/features/container/utils/get-title-from-url.ts new file mode 100644 index 00000000000..dd05c7ecea9 --- /dev/null +++ b/src/app/features/container/utils/get-title-from-url.ts @@ -0,0 +1,35 @@ +import { RouteUrls } from '@shared/route-urls'; + +export function getTitleFromUrl(pathname: RouteUrls) { + if (pathname.match(RouteUrls.SendCryptoAsset)) { + // don't show send on first step of send flow + if (pathname === RouteUrls.SendCryptoAsset) return undefined; + return 'Send'; + } + + switch (pathname) { + case RouteUrls.AddNetwork: + return 'Add a network'; + case RouteUrls.BitcoinContractList: + return 'Bitcoin Contracts'; + case RouteUrls.BitcoinContractLockSuccess: + return 'Locked Bitcoin'; + case RouteUrls.SendBrc20ChooseFee: + return 'Choose fee'; + case RouteUrls.SendBrc20Confirmation: + case RouteUrls.SwapReview: + case RouteUrls.SendBrc20Confirmation: + case '/send/btc/confirm': + return 'Review'; + case RouteUrls.Swap: + return 'Swap'; + case RouteUrls.SentStxTxSummary: + case RouteUrls.SentBtcTxSummary: + return 'Sent'; + case RouteUrls.SentBrc20Summary: + return 'Creating transfer inscription'; + case RouteUrls.SendBrc20Confirmation: + default: + return undefined; + } +} diff --git a/src/app/features/container/utils/route-helpers.ts b/src/app/features/container/utils/route-helpers.ts new file mode 100644 index 00000000000..9755ed10abb --- /dev/null +++ b/src/app/features/container/utils/route-helpers.ts @@ -0,0 +1,49 @@ +import { RouteUrls } from '@shared/route-urls'; + +import { isKnownPopupRoute } from './get-popup-header'; + +function isHomePage(pathname: RouteUrls) { + return ( + pathname === RouteUrls.Home || + pathname.match(RouteUrls.Activity) || + pathname.match(RouteUrls.Receive) + ); +} + +export function isLandingPage(pathname: RouteUrls) { + return pathname === RouteUrls.RequestDiagnostics || pathname.match(RouteUrls.Onboarding); // need to match get-started/ledger +} + +const isOnboardingPage = (pathname: RouteUrls) => { + return ( + pathname === RouteUrls.BackUpSecretKey || + pathname === RouteUrls.SetPassword || + pathname === RouteUrls.SignIn || + pathname === RouteUrls.ViewSecretKey + ); +}; + +export function getPageVariant(pathname: RouteUrls) { + if (isHomePage(pathname)) return 'home'; + if (isOnboardingPage(pathname)) return 'onboarding'; + return 'page'; +} + +export function getIsSessionLocked(pathname: RouteUrls) { + return pathname === RouteUrls.Unlock; +} + +export function canGoBack(pathname: RouteUrls) { + if (getIsSessionLocked(pathname) || isKnownPopupRoute(pathname)) { + return false; + } + return true; +} + +export function hideLogo(pathname: RouteUrls) { + return pathname === RouteUrls.RpcGetAddresses; +} + +export function isGetAddressesPopup(pathname: RouteUrls) { + return pathname === RouteUrls.RpcGetAddresses; +} diff --git a/src/app/features/current-account/current-account-avatar.tsx b/src/app/features/current-account/current-account-avatar.tsx index 39296fac380..13e7f6bb145 100644 --- a/src/app/features/current-account/current-account-avatar.tsx +++ b/src/app/features/current-account/current-account-avatar.tsx @@ -3,24 +3,27 @@ import { memo } from 'react'; import { CircleProps } from 'leather-styles/jsx'; import { useCurrentAccountDisplayName } from '@app/common/hooks/account/use-account-names'; -import { useDrawers } from '@app/common/hooks/use-drawers'; -import { AccountAvatar } from '@app/components/account/account-avatar'; import { useCurrentAccountIndex } from '@app/store/accounts/account'; import { useStacksAccounts } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; import { StacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.models'; +import { AccountAvatar } from '@app/ui/components/account/account-avatar/account-avatar'; -export const CurrentAccountAvatar = memo((props: CircleProps) => { +interface CurrentAccountAvatar extends CircleProps { + toggleSwitchAccount(): void; +} +export const CurrentAccountAvatar = memo((props: CurrentAccountAvatar) => { + const { toggleSwitchAccount } = props; const accountIndex = useCurrentAccountIndex(); const accounts = useStacksAccounts(); const currentAccount = accounts[accountIndex] as StacksAccount | undefined; const name = useCurrentAccountDisplayName(); - const { setIsShowingSwitchAccountsState } = useDrawers(); + if (!currentAccount) return null; return ( setIsShowingSwitchAccountsState(true)} + onClick={toggleSwitchAccount} publicKey={currentAccount.stxPublicKey} {...props} /> diff --git a/src/app/features/current-account/popup-header.tsx b/src/app/features/current-account/popup-header.tsx deleted file mode 100644 index b0c2cfc9748..00000000000 --- a/src/app/features/current-account/popup-header.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { Suspense } from 'react'; - -import { Box, HStack, styled } from 'leather-styles/jsx'; - -import { BtcBalance } from '@app/components/balance-btc'; -import { StxBalance } from '@app/components/balance-stx'; -import { LoadingRectangle } from '@app/components/loading-rectangle'; -import { NetworkModeBadge } from '@app/components/network-mode-badge'; -import { CurrentAccountAvatar } from '@app/features/current-account/current-account-avatar'; -import { CurrentAccountName } from '@app/features/current-account/current-account-name'; -import { useConfigBitcoinEnabled } from '@app/query/common/remote-config/remote-config.query'; -import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; -import { Flag } from '@app/ui/components/flag/flag'; - -interface PopupHeaderLayoutProps { - children: React.ReactNode; -} -function PopupHeaderLayout({ children }: PopupHeaderLayoutProps) { - return ( - - {children} - - ); -} - -interface PopupHeaderProps { - displayAddresssBalanceOf?: 'all' | 'stx'; -} -function PopupHeaderSuspense({ displayAddresssBalanceOf = 'stx' }: PopupHeaderProps) { - const account = useCurrentStacksAccount(); - const isBitcoinEnabled = useConfigBitcoinEnabled(); - return ( - - } - > - - - - - - - - {account && displayAddresssBalanceOf === 'stx' && ( - - )} - {isBitcoinEnabled && displayAddresssBalanceOf === 'all' && } - - - - - ); -} - -function PopupHeaderFallback() { - return ( - - - - ); -} - -export function PopupHeader(props: PopupHeaderProps) { - return ( - }> - - - ); -} diff --git a/src/app/features/edit-nonce-drawer/components/edit-nonce-field.tsx b/src/app/features/dialogs/edit-nonce-dialog/components/edit-nonce-field.tsx similarity index 100% rename from src/app/features/edit-nonce-drawer/components/edit-nonce-field.tsx rename to src/app/features/dialogs/edit-nonce-dialog/components/edit-nonce-field.tsx diff --git a/src/app/features/edit-nonce-drawer/components/edit-nonce-form.tsx b/src/app/features/dialogs/edit-nonce-dialog/components/edit-nonce-form.tsx similarity index 100% rename from src/app/features/edit-nonce-drawer/components/edit-nonce-form.tsx rename to src/app/features/dialogs/edit-nonce-dialog/components/edit-nonce-form.tsx diff --git a/src/app/features/edit-nonce-drawer/edit-nonce-drawer.tsx b/src/app/features/dialogs/edit-nonce-dialog/edit-nonce-dialog.tsx similarity index 76% rename from src/app/features/edit-nonce-drawer/edit-nonce-drawer.tsx rename to src/app/features/dialogs/edit-nonce-dialog/edit-nonce-dialog.tsx index d25677dead9..7b4f3d17459 100644 --- a/src/app/features/edit-nonce-drawer/edit-nonce-drawer.tsx +++ b/src/app/features/dialogs/edit-nonce-dialog/edit-nonce-dialog.tsx @@ -8,25 +8,15 @@ import { StacksSendFormValues, StacksTransactionFormValues } from '@shared/model import { useOnMount } from '@app/common/hooks/use-on-mount'; import { openInNewTab } from '@app/common/utils/open-in-new-tab'; -import { BaseDrawer } from '@app/components/drawer/base-drawer'; +import { Dialog } from '@app/ui/components/containers/dialog/dialog'; +import { Header } from '@app/ui/components/containers/headers/header'; import { Link } from '@app/ui/components/link/link'; import { EditNonceForm } from './components/edit-nonce-form'; const url = 'https://www.hiro.so/questions/transactions-advanced-settings'; -function CustomFeeMessaging() { - return ( - - If your transaction has been pending for a long time, its nonce might not be correct. - openInNewTab(url)}> - Learn more. - - - ); -} - -export function EditNonceDrawer() { +export function EditNonceDialog() { const { errors, setFieldError, setFieldValue, validateField, values } = useFormikContext< StacksSendFormValues | StacksTransactionFormValues >(); @@ -36,7 +26,6 @@ export function EditNonceDrawer() { const { search } = useLocation(); useOnMount(() => setLoadedNextNonce(values.nonce)); - const onGoBack = useCallback(() => { if (search) { return navigate('..' + search, { replace: true }); @@ -59,11 +48,16 @@ export function EditNonceDrawer() { }, [loadedNextNonce, onGoBack, setFieldError, setFieldValue, values.nonce]); return ( - + }> - + + If your transaction has been pending for a long time, its nonce might not be correct. + openInNewTab(url)}> + Learn more. + + - + ); } diff --git a/src/app/features/dialogs/high-fee-dialog/high-fee-dialog.tsx b/src/app/features/dialogs/high-fee-dialog/high-fee-dialog.tsx new file mode 100644 index 00000000000..9a6fd09cc73 --- /dev/null +++ b/src/app/features/dialogs/high-fee-dialog/high-fee-dialog.tsx @@ -0,0 +1,74 @@ +import { useEffect, useState } from 'react'; + +import { useFormikContext } from 'formik'; +import { HStack, Stack } from 'leather-styles/jsx'; + +import { + BitcoinSendFormValues, + StacksSendFormValues, + StacksTransactionFormValues, +} from '@shared/models/form.model'; + +import { openInNewTab } from '@app/common/utils/open-in-new-tab'; +import { Button } from '@app/ui/components/button/button'; +import { Dialog } from '@app/ui/components/containers/dialog/dialog'; +import { Link } from '@app/ui/components/link/link'; +import { Caption } from '@app/ui/components/typography/caption'; +import { Title } from '@app/ui/components/typography/title'; +import { ErrorIcon } from '@app/ui/icons'; + +interface HighFeeDialogProps { + learnMoreUrl: string; + isShowing?: boolean; +} + +export function HighFeeDialog({ learnMoreUrl, isShowing = false }: HighFeeDialogProps) { + const [isShowingHighFeeConfirmation, setIsShowingHighFeeConfirmation] = useState(isShowing); + + useEffect(() => { + return () => { + if (isShowingHighFeeConfirmation) setIsShowingHighFeeConfirmation(false); + }; + }, [isShowingHighFeeConfirmation, setIsShowingHighFeeConfirmation]); + + const { handleSubmit, values } = useFormikContext< + BitcoinSendFormValues | StacksSendFormValues | StacksTransactionFormValues + >(); + return ( + setIsShowingHighFeeConfirmation(false)} + > + {isShowingHighFeeConfirmation && ( + + + + + Are you sure you want to pay {values.fee} {values.feeCurrency} in fees for this + transaction? + + + + This action cannot be undone and the fees won't be returned, even if the transaction + fails. + openInNewTab(learnMoreUrl)} size="sm"> + Learn more + + + + + + + + )} + + ); +} diff --git a/src/app/features/increase-fee-drawer/components/fee-multiplier-button.tsx b/src/app/features/dialogs/increase-fee-dialog/components/fee-multiplier-button.tsx similarity index 100% rename from src/app/features/increase-fee-drawer/components/fee-multiplier-button.tsx rename to src/app/features/dialogs/increase-fee-dialog/components/fee-multiplier-button.tsx diff --git a/src/app/features/increase-fee-drawer/components/fee-multiplier.tsx b/src/app/features/dialogs/increase-fee-dialog/components/fee-multiplier.tsx similarity index 100% rename from src/app/features/increase-fee-drawer/components/fee-multiplier.tsx rename to src/app/features/dialogs/increase-fee-dialog/components/fee-multiplier.tsx diff --git a/src/app/features/increase-fee-drawer/components/increase-btc-fee-form.tsx b/src/app/features/dialogs/increase-fee-dialog/components/increase-btc-fee-form.tsx similarity index 100% rename from src/app/features/increase-fee-drawer/components/increase-btc-fee-form.tsx rename to src/app/features/dialogs/increase-fee-dialog/components/increase-btc-fee-form.tsx diff --git a/src/app/features/increase-fee-drawer/components/increase-fee-actions.tsx b/src/app/features/dialogs/increase-fee-dialog/components/increase-fee-actions.tsx similarity index 100% rename from src/app/features/increase-fee-drawer/components/increase-fee-actions.tsx rename to src/app/features/dialogs/increase-fee-dialog/components/increase-fee-actions.tsx diff --git a/src/app/features/increase-fee-drawer/components/increase-fee-field.tsx b/src/app/features/dialogs/increase-fee-dialog/components/increase-fee-field.tsx similarity index 98% rename from src/app/features/increase-fee-drawer/components/increase-fee-field.tsx rename to src/app/features/dialogs/increase-fee-dialog/components/increase-fee-field.tsx index a12414bd881..5cc073b37c1 100644 --- a/src/app/features/increase-fee-drawer/components/increase-fee-field.tsx +++ b/src/app/features/dialogs/increase-fee-dialog/components/increase-fee-field.tsx @@ -53,7 +53,7 @@ export function IncreaseFeeField(props: IncreaseFeeFieldProps): React.JSX.Elemen bg="transparent" border="default" borderRadius="sm" - height="64px" + height="inputHeight" display="block" p="space.04" placeholder="Enter a custom fee" diff --git a/src/app/features/increase-fee-drawer/components/increase-stx-fee-form.tsx b/src/app/features/dialogs/increase-fee-dialog/components/increase-stx-fee-form.tsx similarity index 100% rename from src/app/features/increase-fee-drawer/components/increase-stx-fee-form.tsx rename to src/app/features/dialogs/increase-fee-dialog/components/increase-stx-fee-form.tsx diff --git a/src/app/features/increase-fee-drawer/hooks/use-btc-increase-fee.ts b/src/app/features/dialogs/increase-fee-dialog/hooks/use-btc-increase-fee.ts similarity index 100% rename from src/app/features/increase-fee-drawer/hooks/use-btc-increase-fee.ts rename to src/app/features/dialogs/increase-fee-dialog/hooks/use-btc-increase-fee.ts diff --git a/src/app/features/increase-fee-drawer/hooks/use-selected-tx.ts b/src/app/features/dialogs/increase-fee-dialog/hooks/use-selected-tx.ts similarity index 100% rename from src/app/features/increase-fee-drawer/hooks/use-selected-tx.ts rename to src/app/features/dialogs/increase-fee-dialog/hooks/use-selected-tx.ts diff --git a/src/app/features/increase-fee-drawer/increase-btc-fee-drawer.tsx b/src/app/features/dialogs/increase-fee-dialog/increase-btc-fee-dialog.tsx similarity index 69% rename from src/app/features/increase-fee-drawer/increase-btc-fee-drawer.tsx rename to src/app/features/dialogs/increase-fee-dialog/increase-btc-fee-dialog.tsx index 16ade832348..ae67ffb5b9d 100644 --- a/src/app/features/increase-fee-drawer/increase-btc-fee-drawer.tsx +++ b/src/app/features/dialogs/increase-fee-dialog/increase-btc-fee-dialog.tsx @@ -6,16 +6,10 @@ import { RouteUrls } from '@shared/route-urls'; import { useLocationStateWithCache } from '@app/common/hooks/use-location-state'; import { IncreaseBtcFeeForm } from './components/increase-btc-fee-form'; -import { IncreaseFeeDrawer } from './increase-fee-drawer'; +import { IncreaseFeeDialog } from './increase-fee-dialog'; -function useIncreaseBtcFeeDrawerState() { - return { - tx: useLocationStateWithCache('btcTx') as BitcoinTx, - }; -} - -export function IncreaseBtcFeeDrawer() { - const { tx } = useIncreaseBtcFeeDrawerState(); +export function IncreaseBtcFeeDialog() { + const tx = useLocationStateWithCache('btcTx') as BitcoinTx; const navigate = useNavigate(); const location = useLocation(); @@ -26,7 +20,7 @@ export function IncreaseBtcFeeDrawer() { if (!tx) return null; return ( - } onClose={onClose} isShowing={location.pathname === RouteUrls.IncreaseBtcFee} diff --git a/src/app/features/increase-fee-drawer/increase-fee-drawer.tsx b/src/app/features/dialogs/increase-fee-dialog/increase-fee-dialog.tsx similarity index 67% rename from src/app/features/increase-fee-drawer/increase-fee-drawer.tsx rename to src/app/features/dialogs/increase-fee-dialog/increase-fee-dialog.tsx index b642400598a..09c18db32bb 100644 --- a/src/app/features/increase-fee-drawer/increase-fee-drawer.tsx +++ b/src/app/features/dialogs/increase-fee-dialog/increase-fee-dialog.tsx @@ -3,19 +3,24 @@ import { Outlet } from 'react-router-dom'; import { Flex, Stack } from 'leather-styles/jsx'; -import { BaseDrawer } from '@app/components/drawer/base-drawer'; +import { Dialog } from '@app/ui/components/containers/dialog/dialog'; +import { Header } from '@app/ui/components/containers/headers/header'; import { Spinner } from '@app/ui/components/spinner'; import { Caption } from '@app/ui/components/typography/caption'; -interface IncreaseFeeDrawerProps { +interface IncreaseFeeDialogProps { feeForm: React.JSX.Element; onClose(): void; isShowing: boolean; } -export function IncreaseFeeDrawer({ feeForm, onClose, isShowing }: IncreaseFeeDrawerProps) { +export function IncreaseFeeDialog({ feeForm, onClose, isShowing }: IncreaseFeeDialogProps) { return ( <> - + } + > - + ); diff --git a/src/app/features/increase-fee-drawer/increase-fee-sent-drawer.tsx b/src/app/features/dialogs/increase-fee-dialog/increase-fee-sent-dialog.tsx similarity index 60% rename from src/app/features/increase-fee-drawer/increase-fee-sent-drawer.tsx rename to src/app/features/dialogs/increase-fee-dialog/increase-fee-sent-dialog.tsx index 67fff526d0d..0edbf888d6e 100644 --- a/src/app/features/increase-fee-drawer/increase-fee-sent-drawer.tsx +++ b/src/app/features/dialogs/increase-fee-dialog/increase-fee-sent-dialog.tsx @@ -4,21 +4,26 @@ import { Flex } from 'leather-styles/jsx'; import { RouteUrls } from '@shared/route-urls'; -import { BaseDrawer } from '@app/components/drawer/base-drawer'; +import { Dialog } from '@app/ui/components/containers/dialog/dialog'; +import { Header } from '@app/ui/components/containers/headers/header'; import { CheckmarkIcon } from '@app/ui/icons/checkmark-icon'; -export function IncreaseFeeSentDrawer() { +export function IncreaseFeeSentDialog() { const location = useLocation(); const navigate = useNavigate(); const isShowing = location.pathname === RouteUrls.IncreaseFeeSent; return ( <> - navigate(RouteUrls.Home)} title="Confirmed"> + navigate(RouteUrls.Home)} + header={
} + > - +
); diff --git a/src/app/features/increase-fee-drawer/increase-stx-fee-drawer.tsx b/src/app/features/dialogs/increase-fee-dialog/increase-stx-fee-dialog.tsx similarity index 90% rename from src/app/features/increase-fee-drawer/increase-stx-fee-drawer.tsx rename to src/app/features/dialogs/increase-fee-dialog/increase-stx-fee-dialog.tsx index 9c81618759e..3d58aa05701 100644 --- a/src/app/features/increase-fee-drawer/increase-stx-fee-drawer.tsx +++ b/src/app/features/dialogs/increase-fee-dialog/increase-stx-fee-dialog.tsx @@ -7,9 +7,9 @@ import { LoadingKeys, useLoading } from '@app/common/hooks/use-loading'; import { useRawTxIdState } from '@app/store/transactions/raw.hooks'; import { IncreaseStxFeeForm } from './components/increase-stx-fee-form'; -import { IncreaseFeeDrawer } from './increase-fee-drawer'; +import { IncreaseFeeDialog } from './increase-fee-dialog'; -export function IncreaseStxFeeDrawer() { +export function IncreaseStxFeeDialog() { const [rawTxId, setRawTxId] = useRawTxIdState(); const { isLoading, setIsIdle } = useLoading(LoadingKeys.INCREASE_FEE_DRAWER); const navigate = useNavigate(); @@ -32,7 +32,7 @@ export function IncreaseStxFeeDrawer() { }, [isLoading, rawTxId, setIsIdle, setRawTxId, txIdFromParams]); return ( - } onClose={onClose} isShowing={location.pathname === RouteUrls.IncreaseStxFee} diff --git a/src/app/features/leather-intro-dialog/confetti-config.ts b/src/app/features/dialogs/leather-intro-dialog/confetti-config.ts similarity index 100% rename from src/app/features/leather-intro-dialog/confetti-config.ts rename to src/app/features/dialogs/leather-intro-dialog/confetti-config.ts diff --git a/src/app/features/leather-intro-dialog/leather-intro-dialog.tsx b/src/app/features/dialogs/leather-intro-dialog/leather-intro-dialog.tsx similarity index 90% rename from src/app/features/leather-intro-dialog/leather-intro-dialog.tsx rename to src/app/features/dialogs/leather-intro-dialog/leather-intro-dialog.tsx index e6e004686fb..dc59d5f6e00 100644 --- a/src/app/features/leather-intro-dialog/leather-intro-dialog.tsx +++ b/src/app/features/dialogs/leather-intro-dialog/leather-intro-dialog.tsx @@ -4,8 +4,6 @@ import { Outlet, Route, useNavigate } from 'react-router-dom'; import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; import { delay } from '@app/common/utils'; import { openInNewTab } from '@app/common/utils/open-in-new-tab'; -import { useAppDispatch } from '@app/store'; -import { settingsActions } from '@app/store/settings/settings.actions'; import { LeatherIntroDialog, @@ -38,8 +36,6 @@ export function useLeatherIntroDialogContext() { function LeatherIntroDialogContainer() { const analytics = useAnalytics(); const navigate = useNavigate(); - const dispatch = useAppDispatch(); - async function onRevealNewName() { void analytics.track('new_brand_reveal_name'); await delay(4000); @@ -48,7 +44,6 @@ function LeatherIntroDialogContainer() { async function onAcceptTerms() { void analytics.track('new_brand_accept_terms'); - dispatch(settingsActions.setHasApprovedNewBrand()); navigate('../', { replace: true }); } diff --git a/src/app/features/leather-intro-dialog/leather-intro-steps.tsx b/src/app/features/dialogs/leather-intro-dialog/leather-intro-steps.tsx similarity index 100% rename from src/app/features/leather-intro-dialog/leather-intro-steps.tsx rename to src/app/features/dialogs/leather-intro-dialog/leather-intro-steps.tsx diff --git a/src/app/features/switch-account-drawer/components/account-list-unavailable.tsx b/src/app/features/dialogs/switch-account-dialog/components/account-list-unavailable.tsx similarity index 100% rename from src/app/features/switch-account-drawer/components/account-list-unavailable.tsx rename to src/app/features/dialogs/switch-account-dialog/components/account-list-unavailable.tsx diff --git a/src/app/features/switch-account-drawer/components/switch-account-list-item.tsx b/src/app/features/dialogs/switch-account-dialog/components/switch-account-list-item.tsx similarity index 95% rename from src/app/features/switch-account-drawer/components/switch-account-list-item.tsx rename to src/app/features/dialogs/switch-account-dialog/components/switch-account-list-item.tsx index 384fb50567c..f71e899aee4 100644 --- a/src/app/features/switch-account-drawer/components/switch-account-list-item.tsx +++ b/src/app/features/dialogs/switch-account-dialog/components/switch-account-list-item.tsx @@ -9,8 +9,7 @@ import { AccountListItemLayout } from '@app/components/account/account-list-item import { AccountNameLayout } from '@app/components/account/account-name'; import { useNativeSegwitSigner } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks'; import { useStacksAccounts } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; - -import { AccountAvatarItem } from '../../../components/account/account-avatar-item'; +import { AccountAvatarItem } from '@app/ui/components/account/account-avatar/account-avatar-item'; interface SwitchAccountListItemProps { handleClose(): void; diff --git a/src/app/features/switch-account-drawer/components/switch-account-list.tsx b/src/app/features/dialogs/switch-account-dialog/components/switch-account-list.tsx similarity index 79% rename from src/app/features/switch-account-drawer/components/switch-account-list.tsx rename to src/app/features/dialogs/switch-account-dialog/components/switch-account-list.tsx index 3b51ffbbda5..bf40683c526 100644 --- a/src/app/features/switch-account-drawer/components/switch-account-list.tsx +++ b/src/app/features/dialogs/switch-account-dialog/components/switch-account-list.tsx @@ -1,6 +1,7 @@ -import { memo } from 'react'; +import { ReactNode, memo } from 'react'; import { Virtuoso } from 'react-virtuoso'; +import { css } from 'leather-styles/css'; import { Box } from 'leather-styles/jsx'; import { useWalletType } from '@app/common/use-wallet-type'; @@ -11,16 +12,22 @@ interface SwitchAccountListProps { handleClose(): void; currentAccountIndex: number; addressesNum: number; + footer?: ReactNode; } export const SwitchAccountList = memo( ({ currentAccountIndex, handleClose, addressesNum }: SwitchAccountListProps) => { const { whenWallet } = useWalletType(); + { + /* // TODO check Kyrans margin needed */ + } return ( ( diff --git a/src/app/features/dialogs/switch-account-dialog/switch-account-dialog.tsx b/src/app/features/dialogs/switch-account-dialog/switch-account-dialog.tsx new file mode 100644 index 00000000000..ef853657885 --- /dev/null +++ b/src/app/features/dialogs/switch-account-dialog/switch-account-dialog.tsx @@ -0,0 +1,62 @@ +import { memo } from 'react'; + +import { useCreateAccount } from '@app/common/hooks/account/use-create-account'; +import { useWalletType } from '@app/common/use-wallet-type'; +import { useCurrentAccountIndex } from '@app/store/accounts/account'; +import { useFilteredBitcoinAccounts } from '@app/store/accounts/blockchain/bitcoin/bitcoin.ledger'; +import { useStacksAccounts } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; +import { Button } from '@app/ui/components/button/button'; +import { Dialog, DialogProps } from '@app/ui/components/containers/dialog/dialog'; +import { Footer } from '@app/ui/components/containers/footers/footer'; +import { Header } from '@app/ui/components/containers/headers/header'; + +import { AccountListUnavailable } from './components/account-list-unavailable'; +import { SwitchAccountList } from './components/switch-account-list'; + +export const SwitchAccountDialog = memo(({ isShowing, onClose }: DialogProps) => { + const currentAccountIndex = useCurrentAccountIndex(); + const createAccount = useCreateAccount(); + const { whenWallet } = useWalletType(); + + const stacksAccounts = useStacksAccounts(); + const bitcoinAccounts = useFilteredBitcoinAccounts(); + const btcAddressesNum = bitcoinAccounts.length / 2; + const stacksAddressesNum = stacksAccounts.length; + + const onCreateAccount = () => { + createAccount(); + onClose(); + }; + + if (isShowing && stacksAddressesNum === 0 && btcAddressesNum === 0) { + return ; + } + // #4370 SMELL without this early return the wallet crashes on new install with + // : Wallet is neither of type `ledger` nor `software` + // FIXME remove this when adding Create Account to Ledger in #2502 #4983 + if (!isShowing) return null; + + return ( + } + isShowing={isShowing} + onClose={onClose} + footer={whenWallet({ + software: ( +
+ +
+ ), + ledger: <>, + })} + > + +
+ ); +}); diff --git a/src/app/features/errors/app-error-boundary.tsx b/src/app/features/errors/app-error-boundary.tsx index f13964586c5..e0b32cee18b 100644 --- a/src/app/features/errors/app-error-boundary.tsx +++ b/src/app/features/errors/app-error-boundary.tsx @@ -2,8 +2,6 @@ import { Box, Stack, styled } from 'leather-styles/jsx'; import { Prism } from '@app/common/clarity-prism'; import { HasChildren } from '@app/common/has-children'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; -import { Header } from '@app/components/header'; import { ErrorBoundary, FallbackProps, useErrorHandler } from '@app/features/errors/error-boundary'; import { openGithubIssue } from '@app/features/errors/utils'; import { useErrorStackTraceState } from '@app/store/ui/ui.hooks'; @@ -13,8 +11,6 @@ import { Title } from '@app/ui/components/typography/title'; function ErrorFallback({ error, resetErrorBoundary }: FallbackProps) { const [value] = useErrorStackTraceState(); - useRouteHeader(
); - return ( Something went wrong diff --git a/src/app/features/high-fee-drawer/components/high-fee-confirmation.tsx b/src/app/features/high-fee-drawer/components/high-fee-confirmation.tsx deleted file mode 100644 index 51aaa6015b2..00000000000 --- a/src/app/features/high-fee-drawer/components/high-fee-confirmation.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { useFormikContext } from 'formik'; -import { HStack, Stack } from 'leather-styles/jsx'; - -import { - BitcoinSendFormValues, - StacksSendFormValues, - StacksTransactionFormValues, -} from '@shared/models/form.model'; - -import { useDrawers } from '@app/common/hooks/use-drawers'; -import { openInNewTab } from '@app/common/utils/open-in-new-tab'; -import { Button } from '@app/ui/components/button/button'; -import { Link } from '@app/ui/components/link/link'; -import { Caption } from '@app/ui/components/typography/caption'; -import { Title } from '@app/ui/components/typography/title'; - -export function HighFeeConfirmation({ learnMoreUrl }: { learnMoreUrl: string }) { - const { handleSubmit, values } = useFormikContext< - BitcoinSendFormValues | StacksSendFormValues | StacksTransactionFormValues - >(); - const { setIsShowingHighFeeConfirmation } = useDrawers(); - - return ( - - - Are you sure you want to pay {values.fee} {values.feeCurrency} in fees for this transaction? - - - This action cannot be undone and the fees won't be returned, even if the transaction fails.{' '} - openInNewTab(learnMoreUrl)} size="sm"> - Learn more - - - - - - - - ); -} diff --git a/src/app/features/high-fee-drawer/high-fee-drawer.tsx b/src/app/features/high-fee-drawer/high-fee-drawer.tsx deleted file mode 100644 index fa8d6d877df..00000000000 --- a/src/app/features/high-fee-drawer/high-fee-drawer.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { useEffect } from 'react'; - -import { useDrawers } from '@app/common/hooks/use-drawers'; -import { ControlledDrawer } from '@app/components/drawer/controlled-drawer'; -import { ErrorIcon } from '@app/ui/icons/error-icon'; - -import { HighFeeConfirmation } from './components/high-fee-confirmation'; - -export function HighFeeDrawer(props: { learnMoreUrl: string }) { - const { learnMoreUrl } = props; - const { isShowingHighFeeConfirmation, setIsShowingHighFeeConfirmation } = useDrawers(); - - useEffect(() => { - return () => { - if (isShowingHighFeeConfirmation) setIsShowingHighFeeConfirmation(false); - }; - }, [isShowingHighFeeConfirmation, setIsShowingHighFeeConfirmation]); - - return ( - } - isShowing={isShowingHighFeeConfirmation} - onClose={() => setIsShowingHighFeeConfirmation(false)} - > - {isShowingHighFeeConfirmation && } - - ); -} diff --git a/src/app/features/hiro-messages/in-app-messages.tsx b/src/app/features/hiro-messages/in-app-messages.tsx index 1d5d0d4a547..3a74216854e 100644 --- a/src/app/features/hiro-messages/in-app-messages.tsx +++ b/src/app/features/hiro-messages/in-app-messages.tsx @@ -7,6 +7,7 @@ import { useDismissedMessageIds } from '@app/store/settings/settings.selectors'; import { HiroMessageItem } from './components/in-app-message-item'; +// See wallet-config.md for instructions on testing InAppMessages export function InAppMessages(props: FlexProps) { const messages = useRemoteLeatherMessages(); diff --git a/src/app/features/html-head/head-provider.tsx b/src/app/features/html-head/head-provider.tsx index fb1f9680572..2b5e756b58a 100644 --- a/src/app/features/html-head/head-provider.tsx +++ b/src/app/features/html-head/head-provider.tsx @@ -1,12 +1,9 @@ import { Link, HeadProvider as ReastHeadProvider, Title } from 'react-head'; -import { useNewBrandApprover } from '@app/store/settings/settings.selectors'; - export function HeadProvider() { - const { hasApprovedNewBrand } = useNewBrandApprover(); return ( - {hasApprovedNewBrand ? : } + ); } @@ -20,12 +17,3 @@ function LeatherMetaTags() { ); } - -function HiroMetaTags() { - return ( - <> - Hiro Wallet - - - ); -} diff --git a/src/app/features/ledger/components/ledger-wrapper.tsx b/src/app/features/ledger/components/ledger-wrapper.tsx index 7f5ca90632b..07b7a82d4b0 100644 --- a/src/app/features/ledger/components/ledger-wrapper.tsx +++ b/src/app/features/ledger/components/ledger-wrapper.tsx @@ -6,7 +6,7 @@ interface LedgerWrapperProps extends BoxProps { export function LedgerWrapper({ image, children, ...props }: LedgerWrapperProps) { return ( - + {image && {image}} {children} diff --git a/src/app/features/ledger/flows/jwt-signing/ledger-sign-jwt-container.tsx b/src/app/features/ledger/flows/jwt-signing/ledger-sign-jwt-container.tsx index c1b718944f7..d28a93ce2b7 100644 --- a/src/app/features/ledger/flows/jwt-signing/ledger-sign-jwt-container.tsx +++ b/src/app/features/ledger/flows/jwt-signing/ledger-sign-jwt-container.tsx @@ -16,7 +16,6 @@ import { useKeyActions } from '@app/common/hooks/use-key-actions'; import { useScrollLock } from '@app/common/hooks/use-scroll-lock'; import { makeLedgerCompatibleUnsignedAuthResponsePayload } from '@app/common/unsafe-auth-response'; import { delay } from '@app/common/utils'; -import { BaseDrawer } from '@app/components/drawer/base-drawer'; import { getStacksAppVersion, prepareLedgerDeviceStacksAppConnection, @@ -26,6 +25,8 @@ import { useCurrentStacksAccount, useStacksAccounts, } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; +import { Dialog } from '@app/ui/components/containers/dialog/dialog'; +import { Header } from '@app/ui/components/containers/headers/header'; import { useLedgerNavigate } from '../../hooks/use-ledger-navigate'; import { checkLockedDeviceError, useLedgerResponseState } from '../../utils/generic-ledger-utils'; @@ -180,15 +181,18 @@ export function LedgerSignJwtContainer() { return ( - + } onClose={onCancelConnectLedger} - pauseOnClickOutside - waitingOnPerformedActionMessage="Ledger device in use" > - + ); } diff --git a/src/app/features/ledger/flows/stacks-message-signing/ledger-stacks-sign-msg-container.tsx b/src/app/features/ledger/flows/stacks-message-signing/ledger-stacks-sign-msg-container.tsx index c16b0d498f0..6554b51c2d2 100644 --- a/src/app/features/ledger/flows/stacks-message-signing/ledger-stacks-sign-msg-container.tsx +++ b/src/app/features/ledger/flows/stacks-message-signing/ledger-stacks-sign-msg-container.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { Outlet, useLocation } from 'react-router-dom'; +import { Outlet, useLocation, useNavigate } from 'react-router-dom'; import { bytesToHex, signatureVrsToRsv } from '@stacks/common'; import { serializeCV } from '@stacks/transactions'; @@ -12,7 +12,6 @@ import { isError } from '@shared/utils'; import { useScrollLock } from '@app/common/hooks/use-scroll-lock'; import { appEvents } from '@app/common/publish-subscribe'; import { delay } from '@app/common/utils'; -import { BaseDrawer } from '@app/components/drawer/base-drawer'; import { getStacksAppVersion, prepareLedgerDeviceStacksAppConnection, @@ -22,6 +21,8 @@ import { } from '@app/features/ledger/utils/stacks-ledger-utils'; import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; import { StacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.models'; +import { Dialog } from '@app/ui/components/containers/dialog/dialog'; +import { Header } from '@app/ui/components/containers/headers/header'; import { useLedgerAnalytics } from '../../hooks/use-ledger-analytics.hook'; import { useLedgerNavigate } from '../../hooks/use-ledger-navigate'; @@ -50,6 +51,7 @@ function LedgerSignMsgData({ children }: LedgerSignMsgDataProps) { type LedgerSignMsgProps = LedgerSignMsgData; function LedgerSignStacksMsg({ account, unsignedMessage }: LedgerSignMsgProps) { useScrollLock(true); + const navigate = useNavigate(); const location = useLocation(); const ledgerNavigate = useLedgerNavigate(); @@ -150,16 +152,19 @@ function LedgerSignStacksMsg({ account, unsignedMessage }: LedgerSignMsgProps) { return ( - navigate(-1) : undefined} isShowing - isWaitingOnPerformedAction={awaitingDeviceConnection || canUserCancelAction} + header={ +
+ } onClose={ledgerNavigate.cancelLedgerAction} - pauseOnClickOutside - waitingOnPerformedActionMessage="Ledger device in use" > - + ); } diff --git a/src/app/features/ledger/generic-flows/request-keys/request-keys-flow.tsx b/src/app/features/ledger/generic-flows/request-keys/request-keys-flow.tsx index 67b4f00dc8c..d1aaec30355 100644 --- a/src/app/features/ledger/generic-flows/request-keys/request-keys-flow.tsx +++ b/src/app/features/ledger/generic-flows/request-keys/request-keys-flow.tsx @@ -1,7 +1,8 @@ import { Outlet, useNavigate } from 'react-router-dom'; import { useScrollLock } from '@app/common/hooks/use-scroll-lock'; -import { BaseDrawer } from '@app/components/drawer/base-drawer'; +import { Dialog } from '@app/ui/components/containers/dialog/dialog'; +import { Header } from '@app/ui/components/containers/headers/header'; import { LedgerRequestKeysContext, LedgerRequestKeysProvider } from './ledger-request-keys.context'; @@ -20,15 +21,13 @@ export function RequestKeysFlow({ return ( - } onClose={onCancelConnectLedger ? onCancelConnectLedger : () => navigate('../')} - pauseOnClickOutside - waitingOnPerformedActionMessage="Ledger device in use" > - + ); } diff --git a/src/app/features/ledger/generic-flows/tx-signing/tx-signing-flow.tsx b/src/app/features/ledger/generic-flows/tx-signing/tx-signing-flow.tsx index ded18d87988..1dcf101f95a 100644 --- a/src/app/features/ledger/generic-flows/tx-signing/tx-signing-flow.tsx +++ b/src/app/features/ledger/generic-flows/tx-signing/tx-signing-flow.tsx @@ -1,8 +1,9 @@ -import { Outlet } from 'react-router-dom'; +import { Outlet, useNavigate } from 'react-router-dom'; import { useLocationState } from '@app/common/hooks/use-location-state'; import { useScrollLock } from '@app/common/hooks/use-scroll-lock'; -import { BaseDrawer } from '@app/components/drawer/base-drawer'; +import { Dialog } from '@app/ui/components/containers/dialog/dialog'; +import { Header } from '@app/ui/components/containers/headers/header'; import { useActionCancellableByUser } from '../../utils/stacks-ledger-utils'; import { LedgerTxSigningContext, LedgerTxSigningProvider } from './ledger-sign-tx.context'; @@ -17,22 +18,26 @@ export function TxSigningFlow({ awaitingDeviceConnection, closeAction, }: TxSigningFlowProps) { + const navigate = useNavigate(); useScrollLock(true); const allowUserToGoBack = useLocationState('goBack'); const canUserCancelAction = useActionCancellableByUser(); return ( - navigate(-1) : undefined} isShowing - isWaitingOnPerformedAction={awaitingDeviceConnection || canUserCancelAction} + header={ +
+ } onClose={closeAction} - pauseOnClickOutside - waitingOnPerformedActionMessage="Ledger device in use" > - + ); } diff --git a/src/app/features/ledger/generic-steps/connect-device/connect-ledger-error.layout.tsx b/src/app/features/ledger/generic-steps/connect-device/connect-ledger-error.layout.tsx index 870f03076bb..a77b4b54a75 100644 --- a/src/app/features/ledger/generic-steps/connect-device/connect-ledger-error.layout.tsx +++ b/src/app/features/ledger/generic-steps/connect-device/connect-ledger-error.layout.tsx @@ -34,7 +34,7 @@ export function ConnectLedgerErrorLayout(props: ConnectLedgerErrorLayoutProps) { const { warningText, onTryAgain, appName } = props; return ( - + diff --git a/src/app/features/ledger/generic-steps/connect-device/connect-ledger-start.tsx b/src/app/features/ledger/generic-steps/connect-device/connect-ledger-start.tsx index 18f1987f45f..1321c5b4626 100644 --- a/src/app/features/ledger/generic-steps/connect-device/connect-ledger-start.tsx +++ b/src/app/features/ledger/generic-steps/connect-device/connect-ledger-start.tsx @@ -5,7 +5,7 @@ import { closeWindow } from '@shared/utils'; import { doesBrowserSupportWebUsbApi, whenPageMode } from '@app/common/utils'; import { openIndexPageInNewTab } from '@app/common/utils/open-in-new-tab'; -import { BaseDrawer } from '@app/components/drawer/base-drawer'; +import { Dialog } from '@app/ui/components/containers/dialog/dialog'; import { immediatelyAttemptLedgerConnection } from '../../hooks/use-when-reattempt-ledger-connection'; import { ConnectLedger } from './connect-ledger'; @@ -35,12 +35,12 @@ export function ConnectLedgerStart() { } return ( - navigate('../')}> + navigate('../')}> connectChain('bitcoin')} connectStacks={() => connectChain('stacks')} showInstructions /> - + ); } diff --git a/src/app/features/ledger/generic-steps/unsupported-browser/unsupported-browser.layout.tsx b/src/app/features/ledger/generic-steps/unsupported-browser/unsupported-browser.layout.tsx index 7e237f351a9..749fdd460f6 100644 --- a/src/app/features/ledger/generic-steps/unsupported-browser/unsupported-browser.layout.tsx +++ b/src/app/features/ledger/generic-steps/unsupported-browser/unsupported-browser.layout.tsx @@ -2,8 +2,8 @@ import { useNavigate } from 'react-router-dom'; import { styled } from 'leather-styles/jsx'; -import { BaseDrawer } from '@app/components/drawer/base-drawer'; import { UnsupportedBrowserImg } from '@app/features/ledger/illustrations/ledger-illu-unsupported-browser'; +import { Dialog } from '@app/ui/components/containers/dialog/dialog'; import { Link } from '@app/ui/components/link/link'; import { LedgerTitle } from '../../components/ledger-title'; @@ -13,16 +13,21 @@ export function UnsupportedBrowserLayout() { const navigate = useNavigate(); return ( - navigate(-1)}> + navigate(-1)}> }> Your browser isn't supported - {' '} - To connect your Ledger with Leather try{' '} - Chrome or{' '} - Brave. + {'To connect your Ledger with Leather try '} + + Chrome + + {' or '} + + Brave + + . - + ); } diff --git a/src/app/features/message-signer/hash-drawer.tsx b/src/app/features/message-signer/hash-drawer.tsx index 42a3d09b096..df9d1a53228 100644 --- a/src/app/features/message-signer/hash-drawer.tsx +++ b/src/app/features/message-signer/hash-drawer.tsx @@ -16,6 +16,7 @@ function ShowHashButton(props: ShowHashButtonProps) { interface HashDrawerProps { hash: string; } + export function HashDrawer(props: HashDrawerProps) { const { hash } = props; const [showHash, setShowHash] = useState(false); @@ -35,7 +36,7 @@ export function HashDrawer(props: HashDrawerProps) { {showHash ? 'Hide hash' : 'Show hash'} - + diff --git a/src/app/features/message-signer/message-preview-box.tsx b/src/app/features/message-signer/message-preview-box.tsx index 0b7a1e4a67c..32009cb5745 100644 --- a/src/app/features/message-signer/message-preview-box.tsx +++ b/src/app/features/message-signer/message-preview-box.tsx @@ -8,12 +8,7 @@ interface MessageBoxProps { } export function MessagePreviewBox({ message, hash }: MessageBoxProps) { return ( - + - - - - - +
+ + +
); } diff --git a/src/app/features/psbt-signer/components/psbt-signer.layout.tsx b/src/app/features/psbt-signer/components/psbt-signer.layout.tsx deleted file mode 100644 index 1016de2b254..00000000000 --- a/src/app/features/psbt-signer/components/psbt-signer.layout.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { Stack } from 'leather-styles/jsx'; - -import { HasChildren } from '@app/common/has-children'; - -export function PsbtSignerLayout({ children }: HasChildren) { - return ( - - {children} - - ); -} diff --git a/src/app/features/psbt-signer/psbt-signer.tsx b/src/app/features/psbt-signer/psbt-signer.tsx index 85dc31a1fdb..ea476a82f77 100644 --- a/src/app/features/psbt-signer/psbt-signer.tsx +++ b/src/app/features/psbt-signer/psbt-signer.tsx @@ -5,23 +5,13 @@ import { getPsbtTxInputs, getPsbtTxOutputs } from '@shared/crypto/bitcoin/bitcoi import { RouteUrls } from '@shared/route-urls'; import { closeWindow, isError } from '@shared/utils'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; import { SignPsbtArgs } from '@app/common/psbt/requests'; -import { PopupHeader } from '@app/features/current-account/popup-header'; import { useOnOriginTabClose } from '@app/routes/hooks/use-on-tab-closed'; import { useCurrentAccountNativeSegwitIndexZeroSigner } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks'; import { useCurrentAccountTaprootIndexZeroSigner } from '@app/store/accounts/blockchain/bitcoin/taproot-account.hooks'; +import { PopupCard } from '@app/ui/components/containers/popup/popup-card'; -import { PsbtInputsAndOutputs } from './components/psbt-inputs-and-outputs/psbt-inputs-and-outputs'; -import { PsbtInputsOutputsTotals } from './components/psbt-inputs-outputs-totals/psbt-inputs-outputs-totals'; -import { PsbtRequestActions } from './components/psbt-request-actions'; -import { PsbtRequestDetailsHeader } from './components/psbt-request-details-header'; -import { PsbtRequestDetailsLayout } from './components/psbt-request-details.layout'; -import { PsbtRequestFee } from './components/psbt-request-fee'; -import { PsbtRequestHeader } from './components/psbt-request-header'; -import { PsbtRequestRaw } from './components/psbt-request-raw'; -import { PsbtRequestSighashWarningLabel } from './components/psbt-request-sighash-warning-label'; -import { PsbtSignerLayout } from './components/psbt-signer.layout'; +import * as Psbt from './components'; import { useParsedPsbt } from './hooks/use-parsed-psbt'; import { usePsbtSigner } from './hooks/use-psbt-signer'; import { PsbtSignerContext, PsbtSignerProvider } from './psbt-signer.context'; @@ -42,8 +32,6 @@ export function PsbtSigner(props: PsbtSignerProps) { const { address: addressTaproot } = useCurrentAccountTaprootIndexZeroSigner(); const { getRawPsbt, getPsbtAsTransaction } = usePsbtSigner(); - useRouteHeader(); - useOnOriginTabClose(() => closeWindow()); const psbtRaw = useMemo(() => { @@ -91,22 +79,22 @@ export function PsbtSigner(props: PsbtSignerProps) { shouldDefaultToAdvancedView, }; - if (shouldDefaultToAdvancedView && psbtRaw) return ; + if (shouldDefaultToAdvancedView && psbtRaw) return ; return ( - - - - {isPsbtMutable ? : null} - - - - {psbtRaw ? : null} - - - - + + + {isPsbtMutable ? : null} + + + + {psbtRaw ? : null} + + + + diff --git a/src/app/features/retrieve-taproot-to-native-segwit/components/retrieve-taproot-to-native-segwit.layout.tsx b/src/app/features/retrieve-taproot-to-native-segwit/components/retrieve-taproot-to-native-segwit.layout.tsx index 8bae581829b..8123674bd31 100644 --- a/src/app/features/retrieve-taproot-to-native-segwit/components/retrieve-taproot-to-native-segwit.layout.tsx +++ b/src/app/features/retrieve-taproot-to-native-segwit/components/retrieve-taproot-to-native-segwit.layout.tsx @@ -1,9 +1,9 @@ import { Flex, styled } from 'leather-styles/jsx'; -import { BaseDrawer } from '@app/components/drawer/base-drawer'; import { BtcAvatarIcon } from '@app/ui/components/avatar/btc-avatar-icon'; import { Button } from '@app/ui/components/button/button'; import { Callout } from '@app/ui/components/callout/callout'; +import { Dialog } from '@app/ui/components/containers/dialog/dialog'; interface RetrieveTaprootToNativeSegwitLayoutProps { isBroadcasting: boolean; @@ -16,7 +16,7 @@ export function RetrieveTaprootToNativeSegwitLayout( ) { const { onClose, onApproveTransaction, isBroadcasting, children } = props; return ( - onClose()}> + onClose()}> @@ -48,6 +48,6 @@ export function RetrieveTaprootToNativeSegwitLayout( Retrieve bitcoin - + ); } diff --git a/src/app/features/secret-key-displayer/secret-key-displayer.tsx b/src/app/features/secret-key-displayer/secret-key-displayer.tsx index 45282345f16..302aedb2f1d 100644 --- a/src/app/features/secret-key-displayer/secret-key-displayer.tsx +++ b/src/app/features/secret-key-displayer/secret-key-displayer.tsx @@ -6,12 +6,12 @@ import { RouteUrls } from '@shared/route-urls'; import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; import { useClipboard } from '@app/common/hooks/use-copy-to-clipboard'; -import { SecretKeyDisplayerLayout } from './secret-key-displayer.layout'; +import { SecretKeyLayout } from '../../ui/components/secret-key/secret-key.layout'; -interface SecretKeyDisplayerProps { +interface SecretKeyProps { secretKey: string; } -export const SecretKeyDisplayer = memo(({ secretKey }: SecretKeyDisplayerProps) => { +export const SecretKey = memo(({ secretKey }: SecretKeyProps) => { const { onCopy, hasCopied } = useClipboard(secretKey || ''); const { pathname } = useLocation(); const analytics = useAnalytics(); @@ -27,7 +27,7 @@ export const SecretKeyDisplayer = memo(({ secretKey }: SecretKeyDisplayerProps) return ( <> - onClick?.(e)} - px="space.04" - py="space.04" - textStyle="label.02" - width="100%" - {...props} - > - {children} - - ); -} diff --git a/src/app/features/settings-dropdown/components/settings-menu-wrapper.tsx b/src/app/features/settings-dropdown/components/settings-menu-wrapper.tsx deleted file mode 100644 index dfe90672396..00000000000 --- a/src/app/features/settings-dropdown/components/settings-menu-wrapper.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { forwardRef } from 'react'; - -import { Box, BoxProps } from 'leather-styles/jsx'; - -interface MenuWrapperProps extends BoxProps { - isShowing: boolean; -} -export const MenuWrapper = forwardRef( - ({ isShowing, ...props }: MenuWrapperProps, ref) => - isShowing ? ( - - ) : null -); diff --git a/src/app/features/settings-dropdown/settings-dropdown.tsx b/src/app/features/settings-dropdown/settings-dropdown.tsx deleted file mode 100644 index 173350a2d29..00000000000 --- a/src/app/features/settings-dropdown/settings-dropdown.tsx +++ /dev/null @@ -1,170 +0,0 @@ -import { useCallback, useRef } from 'react'; -import { useLocation, useNavigate } from 'react-router-dom'; - -import { SettingsSelectors } from '@tests/selectors/settings.selectors'; -import { Box, Flex, HStack } from 'leather-styles/jsx'; - -import { RouteUrls } from '@shared/route-urls'; - -import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; -import { useDrawers } from '@app/common/hooks/use-drawers'; -import { useKeyActions } from '@app/common/hooks/use-key-actions'; -import { useModifierKey } from '@app/common/hooks/use-modifier-key'; -import { useOnClickOutside } from '@app/common/hooks/use-onclickoutside'; -import { useWalletType } from '@app/common/use-wallet-type'; -import { whenPageMode } from '@app/common/utils'; -import { openInNewTab, openIndexPageInNewTab } from '@app/common/utils/open-in-new-tab'; -import { Divider } from '@app/components/layout/divider'; -import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; -import { useHasLedgerKeys, useLedgerDeviceTargetId } from '@app/store/ledger/ledger.selectors'; -import { useCurrentNetworkId } from '@app/store/networks/networks.selectors'; -import { Caption } from '@app/ui/components/typography/caption'; -import { ExternalLinkIcon } from '@app/ui/icons/external-link-icon'; - -import { openFeedbackDialog } from '../feedback-button/feedback-button'; -import { extractDeviceNameFromKnownTargetIds } from '../ledger/utils/generic-ledger-utils'; -import { AdvancedMenuItems } from './components/advanced-menu-items'; -import { LedgerDeviceItemRow } from './components/ledger-item-row'; -import { SettingsMenuItem as MenuItem } from './components/settings-menu-item'; -import { MenuWrapper } from './components/settings-menu-wrapper'; - -export function SettingsDropdown() { - const ref = useRef(null); - const hasGeneratedWallet = !!useCurrentStacksAccount(); - const { lockWallet } = useKeyActions(); - - const { isShowingSettings, setIsShowingSettings } = useDrawers(); - const currentNetworkId = useCurrentNetworkId(); - const navigate = useNavigate(); - const analytics = useAnalytics(); - const { walletType } = useWalletType(); - const targetId = useLedgerDeviceTargetId(); - - const { isPressed: showAdvancedMenuOptions } = useModifierKey('alt', 120); - const location = useLocation(); - - const handleClose = useCallback(() => setIsShowingSettings(false), [setIsShowingSettings]); - - const wrappedCloseCallback = useCallback( - (callback: () => void) => () => { - callback(); - handleClose(); - }, - [handleClose] - ); - - const isLedger = useHasLedgerKeys(); - - useOnClickOutside(ref, isShowingSettings ? handleClose : null, ['settings-menu-btn']); - - // RouteUrls.Activity is nested off / so we need to use a link relative to the route - const linkRelativeType = - location.pathname === `${RouteUrls.Home}${RouteUrls.Activity}` ? 'route' : 'path'; - - return ( - - {isLedger && targetId && ( - - )} - {hasGeneratedWallet && walletType === 'software' && ( - <> - { - navigate(RouteUrls.ViewSecretKey); - })} - > - View Secret Key - - - )} - { - void analytics.track('click_change_theme_menu_item'); - navigate(RouteUrls.ChangeTheme, { - relative: linkRelativeType, - state: { backgroundLocation: location }, - }); - })} - > - Change theme - - {whenPageMode({ - full: null, - popup: ( - { - void analytics.track('click_open_in_new_tab_menu_item'); - openIndexPageInNewTab(location.pathname); - }} - > - - Open in new tab - - - - ), - })} - { - openInNewTab('https://leather.gitbook.io/guides/installing/contact-support'); - })} - > - - Get support - - - - openFeedbackDialog())}>Give feedback - {hasGeneratedWallet ? : null} - { - void analytics.track('click_change_network_menu_item'); - navigate(RouteUrls.SelectNetwork, { - relative: linkRelativeType, - state: { backgroundLocation: location }, - }); - })} - > - - Change network - {currentNetworkId} - - - - - - {showAdvancedMenuOptions && ( - - )} - {hasGeneratedWallet && walletType === 'software' && ( - { - void analytics.track('lock_session'); - void lockWallet(); - navigate(RouteUrls.Unlock); - })} - data-testid="settings-lock" - > - Lock - - )} - - navigate(RouteUrls.SignOutConfirm, { - relative: linkRelativeType, - state: { backgroundLocation: location }, - }) - )} - data-testid={SettingsSelectors.SignOutListItem} - > - Sign out - - - ); -} diff --git a/src/app/features/settings-dropdown/components/advanced-menu-items.tsx b/src/app/features/settings/components/advanced-menu-items.tsx similarity index 77% rename from src/app/features/settings-dropdown/components/advanced-menu-items.tsx rename to src/app/features/settings/components/advanced-menu-items.tsx index 42f812a3c41..e414826d6b1 100644 --- a/src/app/features/settings-dropdown/components/advanced-menu-items.tsx +++ b/src/app/features/settings/components/advanced-menu-items.tsx @@ -10,10 +10,9 @@ import { import { isNumber } from '@shared/utils'; import { Divider } from '@app/components/layout/divider'; +import { DropdownMenu } from '@app/ui/components/dropdown-menu/dropdown-menu'; import { Caption } from '@app/ui/components/typography/caption'; -import { SettingsMenuItem as MenuItem } from './settings-menu-item'; - const isAnEmptyLogsArrayByteThreshold = 7; function isSmallEnoughToBeConsiderdEmptyCache(logSizeInBytes?: number) { @@ -21,12 +20,8 @@ function isSmallEnoughToBeConsiderdEmptyCache(logSizeInBytes?: number) { return logSizeInBytes < isAnEmptyLogsArrayByteThreshold; } -interface AdvancedMenuItemsProps { - closeHandler(fn: () => void): () => void; - settingsShown: boolean; -} -export function AdvancedMenuItems({ closeHandler, settingsShown }: AdvancedMenuItemsProps) { - const { result: logSizeInBytes } = useAsync(async () => getLogSizeInBytes(), [settingsShown]); +export function AdvancedMenuItems() { + const { result: logSizeInBytes } = useAsync(async () => getLogSizeInBytes(), []); const diagnosticLogText = useMemo(() => { const noLogInfoMsg = `There are no logs cached`; @@ -39,28 +34,28 @@ export function AdvancedMenuItems({ closeHandler, settingsShown }: AdvancedMenuI return ( <> - { + { await copyLogsToClipboard(); toast.success('Copied to clipboard'); - })} + }} > Copy diagnostics to clipboard Contains private wallet usage activity - - { + + { await clearBrowserStorageLogs(); toast.success('Diagnostic logs cleared'); - })} + }} > Clear diagnostic information {diagnosticLogText} - + ); diff --git a/src/app/features/settings-dropdown/components/ledger-item-row.tsx b/src/app/features/settings/components/ledger-item-row.tsx similarity index 100% rename from src/app/features/settings-dropdown/components/ledger-item-row.tsx rename to src/app/features/settings/components/ledger-item-row.tsx diff --git a/src/app/pages/select-network/components/network-list-item.layout.tsx b/src/app/features/settings/network/components/network-list-item.layout.tsx similarity index 88% rename from src/app/pages/select-network/components/network-list-item.layout.tsx rename to src/app/features/settings/network/components/network-list-item.layout.tsx index 3faf4f4c132..485e8d6f36d 100644 --- a/src/app/pages/select-network/components/network-list-item.layout.tsx +++ b/src/app/features/settings/network/components/network-list-item.layout.tsx @@ -5,9 +5,7 @@ import { NetworkConfiguration } from '@shared/constants'; import { getUrlHostname } from '@app/common/utils'; import { Button } from '@app/ui/components/button/button'; -import { TrashIcon } from '@app/ui/icons/trash-icon'; - -import { NetworkStatusIndicator } from './network-status-indicator'; +import { CheckmarkIcon, CloudOffIcon, TrashIcon } from '@app/ui/icons'; interface NetworkListItemLayoutProps { networkId: string; @@ -37,7 +35,7 @@ export function NetworkListItemLayout({ unSelectable ? undefined : { - backgroundColor: 'ink.component-background-hover', + bg: 'ink.component-background-hover', } } px="space.05" @@ -56,7 +54,7 @@ export function NetworkListItemLayout({ {getUrlHostname(network.chain.stacks.url)} - + {!isOnline ? : isActive ? : null} {isCustom && ( + + } + > + {Object.keys(networks).map(id => ( + { + selectNetwork(id); + onClose(); + }} + isCustom={!defaultNetworkIds.includes(id)} + onRemoveNetwork={id => { + if (id === currentNetwork.id) networksActions.changeNetwork('mainnet'); + removeNetwork(id); + }} + /> + ))} + + ); +} diff --git a/src/app/features/settings/settings.tsx b/src/app/features/settings/settings.tsx new file mode 100644 index 00000000000..a7ce6e9f329 --- /dev/null +++ b/src/app/features/settings/settings.tsx @@ -0,0 +1,214 @@ +import { useState } from 'react'; +import { useLocation, useNavigate } from 'react-router-dom'; + +import { SettingsSelectors } from '@tests/selectors/settings.selectors'; +import { css } from 'leather-styles/css'; +import { Flex, styled } from 'leather-styles/jsx'; + +import { RouteUrls } from '@shared/route-urls'; + +import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; +import { useKeyActions } from '@app/common/hooks/use-key-actions'; +import { useModifierKey } from '@app/common/hooks/use-modifier-key'; +import { useWalletType } from '@app/common/use-wallet-type'; +import { openInNewTab, openIndexPageInNewTab } from '@app/common/utils/open-in-new-tab'; +import { AppVersion } from '@app/components/app-version'; +import { Divider } from '@app/components/layout/divider'; +import { NetworkDialog } from '@app/features/settings/network/network'; +import { SignOut } from '@app/features/settings/sign-out/sign-out-confirm'; +import { ThemeDialog } from '@app/features/settings/theme/theme-dialog'; +import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; +import { useHasLedgerKeys, useLedgerDeviceTargetId } from '@app/store/ledger/ledger.selectors'; +import { useCurrentNetworkId } from '@app/store/networks/networks.selectors'; +import { DropdownMenu } from '@app/ui/components/dropdown-menu/dropdown-menu'; +import { Flag } from '@app/ui/components/flag/flag'; +import { Caption } from '@app/ui/components/typography/caption'; +import { + ExitIcon, + ExpandIcon, + ExternalLinkIcon, + KeyIcon, + LockIcon, + MegaphoneIcon, + SunInCloudIcon, + SupportIcon, + SwapIcon, + WorldIcon, +} from '@app/ui/icons/'; + +import { openFeedbackDialog } from '../feedback-button/feedback-button'; +import { extractDeviceNameFromKnownTargetIds } from '../ledger/utils/generic-ledger-utils'; +import { AdvancedMenuItems } from './components/advanced-menu-items'; +import { LedgerDeviceItemRow } from './components/ledger-item-row'; + +interface SettingsProps { + triggerButton: React.ReactNode; + toggleSwitchAccount(): void; +} +export function Settings({ triggerButton, toggleSwitchAccount }: SettingsProps) { + const [showSignOut, setShowSignOut] = useState(false); + const [showChangeTheme, setShowChangeTheme] = useState(false); + const [showChangeNetwork, setShowChangeNetwork] = useState(false); + const hasGeneratedWallet = !!useCurrentStacksAccount(); + const { lockWallet } = useKeyActions(); + + const currentNetworkId = useCurrentNetworkId(); + const navigate = useNavigate(); + const analytics = useAnalytics(); + const { walletType } = useWalletType(); + const targetId = useLedgerDeviceTargetId(); + + const location = useLocation(); + + const isLedger = useHasLedgerKeys(); + const { isPressed: showAdvancedMenuOptions } = useModifierKey('alt', 120); + + return ( + <> + + {triggerButton} + + + + {isLedger && targetId && ( + + + + )} + {hasGeneratedWallet && ( + + } textStyle="label.02"> + Switch account + + + )} + {hasGeneratedWallet && walletType === 'software' && ( + navigate(RouteUrls.ViewSecretKey)} + > + } textStyle="label.02"> + View Secret Key + + + )} + + { + void analytics.track('click_open_in_new_tab_menu_item'); + openIndexPageInNewTab(location.pathname); + }} + > + } textStyle="label.02"> + Maximize + + + + + { + void analytics.track('click_change_network_menu_item'); + setShowChangeNetwork(!showChangeNetwork); + }} + > + }> + + Change network + + {currentNetworkId} + + + + + + { + void analytics.track('click_change_theme_menu_item'); + setShowChangeTheme(!showChangeTheme); + }} + > + }> + + Change theme + + + + + + + { + openInNewTab('https://leather.gitbook.io/guides/installing/contact-support'); + }} + > + } textStyle="label.02"> + + Get support + + + + + openFeedbackDialog()}> + } textStyle="label.02"> + Give feedback + + + + + + + {showAdvancedMenuOptions && } + {hasGeneratedWallet && walletType === 'software' && ( + { + void analytics.track('lock_session'); + void lockWallet(); + navigate(RouteUrls.Unlock); + }} + data-testid={SettingsSelectors.LockListItem} + > + } textStyle="label.02"> + Lock + + + )} + + setShowSignOut(!showSignOut)} + data-testid={SettingsSelectors.SignOutListItem} + > + } textStyle="label.02"> + Sign out + + + + + + + + setShowSignOut(!showSignOut)} /> + setShowChangeTheme(!showChangeTheme)} + /> + setShowChangeNetwork(!showChangeNetwork)} + /> + + ); +} diff --git a/src/app/features/settings/sign-out/sign-out-confirm.tsx b/src/app/features/settings/sign-out/sign-out-confirm.tsx new file mode 100644 index 00000000000..8e1be6d51c2 --- /dev/null +++ b/src/app/features/settings/sign-out/sign-out-confirm.tsx @@ -0,0 +1,36 @@ +import { useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; + +import { RouteUrls } from '@shared/route-urls'; + +import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; +import { useKeyActions } from '@app/common/hooks/use-key-actions'; + +import { SignOutDialog } from './sign-out'; + +interface SignOutProps { + isShowing: boolean; + onClose(): void; +} + +export function SignOut({ isShowing = false, onClose }: SignOutProps) { + const analytics = useAnalytics(); + + // TODO 4370 check if this is enough to track views of previous sign-out route + useEffect(() => void analytics.track('sign-out'), [analytics]); + const { signOut } = useKeyActions(); + const navigate = useNavigate(); + // FIXME same bug as SwitchAcccount dialog where we call hooks from useWalletType when no wallet yet set + if (!isShowing) return null; + return ( + { + void signOut().finally(() => { + navigate(RouteUrls.Onboarding); + }); + }} + onClose={onClose} + /> + ); +} diff --git a/src/app/features/settings/sign-out/sign-out.tsx b/src/app/features/settings/sign-out/sign-out.tsx new file mode 100644 index 00000000000..a2112056695 --- /dev/null +++ b/src/app/features/settings/sign-out/sign-out.tsx @@ -0,0 +1,105 @@ +import { SettingsSelectors } from '@tests/selectors/settings.selectors'; +import { useFormik } from 'formik'; +import { Flex, HStack, styled } from 'leather-styles/jsx'; + +import { useWalletType } from '@app/common/use-wallet-type'; +import { Button } from '@app/ui/components/button/button'; +import { Callout } from '@app/ui/components/callout/callout'; +import { Dialog, DialogProps } from '@app/ui/components/containers/dialog/dialog'; +import { Footer } from '@app/ui/components/containers/footers/footer'; +import { Header } from '@app/ui/components/containers/headers/header'; + +interface SignOutDialogProps extends DialogProps { + onUserDeleteWallet(): void; +} +export function SignOutDialog({ isShowing, onUserDeleteWallet, onClose }: SignOutDialogProps) { + const { whenWallet, walletType } = useWalletType(); + const form = useFormik({ + initialValues: { + confirmBackup: whenWallet({ ledger: true, software: false }), + confirmPasswordDisable: whenWallet({ ledger: true, software: false }), + }, + onSubmit() { + onUserDeleteWallet(); + }, + }); + + const canSignOut = form.values.confirmBackup && form.values.confirmPasswordDisable; + + return ( + } + isShowing={isShowing} + onClose={onClose} + footer={ +
+ + +
+ } + > + + {whenWallet({ + software: + "Back up your Secret Key before signing out. You'll be asked for your Secret Key on your next login.", + ledger: + "When you sign out, you'll need to reconnect your Ledger to sign back into your wallet.", + })} + + + + + + + + + I have backed up my Secret Key. + + + + + + + + I understand that my password will not give me access to my wallet after I sign out. + + + + + +
+ ); +} diff --git a/src/app/features/theme-drawer/theme-list.tsx b/src/app/features/settings/theme/theme-dialog.tsx similarity index 71% rename from src/app/features/theme-drawer/theme-list.tsx rename to src/app/features/settings/theme/theme-dialog.tsx index 4cdd87616e7..ac2217059ab 100644 --- a/src/app/features/theme-drawer/theme-list.tsx +++ b/src/app/features/settings/theme/theme-dialog.tsx @@ -1,13 +1,13 @@ import { useCallback } from 'react'; -import { Flex, FlexProps } from 'leather-styles/jsx'; - import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; import { UserSelectedTheme, themeLabelMap, useThemeSwitcher } from '@app/common/theme-provider'; +import { Dialog, DialogProps } from '@app/ui/components/containers/dialog/dialog'; +import { Header } from '@app/ui/components/containers/headers/header'; import { ThemeListItem } from './theme-list-item'; -export function ThemeList(props: FlexProps) { +export function ThemeDialog({ isShowing, onClose }: DialogProps) { const themes = Object.keys(themeLabelMap) as UserSelectedTheme[]; const analytics = useAnalytics(); const { setUserSelectedTheme } = useThemeSwitcher(); @@ -25,7 +25,11 @@ export function ThemeList(props: FlexProps) { const { userSelectedTheme } = useThemeSwitcher(); return ( - + } + isShowing={isShowing} + onClose={onClose} + > {themes.map(theme => ( ))} - + ); } diff --git a/src/app/features/theme-drawer/theme-list-item-layout.tsx b/src/app/features/settings/theme/theme-list-item.tsx similarity index 54% rename from src/app/features/theme-drawer/theme-list-item-layout.tsx rename to src/app/features/settings/theme/theme-list-item.tsx index 716e05ea1ee..33c72298fd9 100644 --- a/src/app/features/theme-drawer/theme-list-item-layout.tsx +++ b/src/app/features/settings/theme/theme-list-item.tsx @@ -1,17 +1,21 @@ +import { useCallback } from 'react'; + import { Box, Flex, styled } from 'leather-styles/jsx'; -import { CheckmarkIcon } from '@app/ui/icons/checkmark-icon'; +import { UserSelectedTheme, getThemeLabel } from '@app/common/theme-provider'; +import { CheckmarkIcon } from '@app/ui/icons'; interface ThemeListItemProps { - themeLabel: string; + theme: UserSelectedTheme; + onThemeSelected(theme: UserSelectedTheme): void; isActive: boolean; - onThemeItemSelect(): void; } -export function ThemeListItemLayout({ - themeLabel, - isActive, - onThemeItemSelect, -}: ThemeListItemProps) { +export function ThemeListItem({ theme, onThemeSelected, isActive }: ThemeListItemProps) { + const themeLabel = getThemeLabel(theme); + const onThemeItemSelect = useCallback(() => { + onThemeSelected(theme); + }, [onThemeSelected, theme]); + return ( ); useOnOriginTabClose(() => closeWindow()); if (!tabId) return null; diff --git a/src/app/features/stacks-transaction-request/hooks/use-stacks-transaction-summary.ts b/src/app/features/stacks-transaction-request/hooks/use-stacks-transaction-summary.ts index bdcab79db67..309f3b9acca 100644 --- a/src/app/features/stacks-transaction-request/hooks/use-stacks-transaction-summary.ts +++ b/src/app/features/stacks-transaction-request/hooks/use-stacks-transaction-summary.ts @@ -34,7 +34,6 @@ export function useStacksTransactionSummary(token: CryptoCurrencies) { function formSentSummaryTxState(txId: string, signedTx: StacksTransaction, decimals?: number) { return { state: { - hasHeaderTitle: true, txLink: { blockchain: 'stacks', txid: txId || '', diff --git a/src/app/features/stacks-transaction-request/stacks-transaction-signer.tsx b/src/app/features/stacks-transaction-request/stacks-transaction-signer.tsx index 96fdb31a3f1..f3383c43070 100644 --- a/src/app/features/stacks-transaction-request/stacks-transaction-signer.tsx +++ b/src/app/features/stacks-transaction-request/stacks-transaction-signer.tsx @@ -1,3 +1,4 @@ +import { useState } from 'react'; import { Outlet, useLocation, useNavigate } from 'react-router-dom'; import { StacksTransaction } from '@stacks/transactions'; @@ -12,14 +13,12 @@ import { RouteUrls } from '@shared/route-urls'; import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; import { useOnMount } from '@app/common/hooks/use-on-mount'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; import { stxToMicroStx } from '@app/common/money/unit-conversion'; import { stxFeeValidator } from '@app/common/validation/forms/fee-validators'; import { nonceValidator } from '@app/common/validation/nonce-validators'; import { NonceSetter } from '@app/components/nonce-setter'; -import { PopupHeader } from '@app/features/current-account/popup-header'; +import { HighFeeDialog } from '@app/features/dialogs/high-fee-dialog/high-fee-dialog'; import { RequestingTabClosedWarningMessage } from '@app/features/errors/requesting-tab-closed-error-msg'; -import { HighFeeDrawer } from '@app/features/high-fee-drawer/high-fee-drawer'; import { ContractCallDetails } from '@app/features/stacks-transaction-request/contract-call-details/contract-call-details'; import { ContractDeployDetails } from '@app/features/stacks-transaction-request/contract-deploy-details/contract-deploy-details'; import { PageTop } from '@app/features/stacks-transaction-request/page-top'; @@ -52,6 +51,7 @@ export function StacksTransactionSigner({ onSignStacksTransaction, isMultisig, }: StacksTransactionSignerProps) { + const [isShowingHighFeeConfirmation, setIsShowingHighFeeConfirmation] = useState(false); const transactionRequest = useTransactionRequestState(); const { data: stxFees } = useCalculateStacksTxFees(stacksTransaction); const analytics = useAnalytics(); @@ -60,8 +60,6 @@ export function StacksTransactionSigner({ const { data: nextNonce } = useNextNonce(); const { search } = useLocation(); - useRouteHeader(); - useOnMount(() => { void analytics.track('view_transaction_signing'), [analytics]; }); @@ -133,8 +131,13 @@ export function StacksTransactionSigner({ )} - - + setIsShowingHighFeeConfirmation(true)} + /> + )} diff --git a/src/app/features/stacks-transaction-request/submit-action.tsx b/src/app/features/stacks-transaction-request/submit-action.tsx index 85c7b757881..45fc22d70e3 100644 --- a/src/app/features/stacks-transaction-request/submit-action.tsx +++ b/src/app/features/stacks-transaction-request/submit-action.tsx @@ -5,14 +5,16 @@ import { HIGH_FEE_AMOUNT_STX } from '@shared/constants'; import { StacksTransactionFormValues } from '@shared/models/form.model'; import { isEmpty } from '@shared/utils'; -import { useDrawers } from '@app/common/hooks/use-drawers'; import { useTransactionError } from '@app/features/stacks-transaction-request/hooks/use-transaction-error'; import { Button } from '@app/ui/components/button/button'; -export function SubmitAction() { +interface SubmitActionProps { + setIsShowingHighFeeConfirmation(): void; +} +export function SubmitAction({ setIsShowingHighFeeConfirmation }: SubmitActionProps) { const { handleSubmit, values, validateForm, isSubmitting } = useFormikContext(); - const { isShowingHighFeeConfirmation, setIsShowingHighFeeConfirmation } = useDrawers(); + const error = useTransactionError(); const isDisabled = !!error || Number(values.fee) < 0; @@ -21,7 +23,7 @@ export function SubmitAction() { // Check for errors before showing the high fee confirmation const formErrors = await validateForm(); if (isEmpty(formErrors) && Number(values.fee) > HIGH_FEE_AMOUNT_STX) { - return setIsShowingHighFeeConfirmation(!isShowingHighFeeConfirmation); + return setIsShowingHighFeeConfirmation(); } handleSubmit(); }; diff --git a/src/app/features/stacks-transaction-request/transaction-error/error-messages.tsx b/src/app/features/stacks-transaction-request/transaction-error/error-messages.tsx index 2c2d0c0b984..f88783c820f 100644 --- a/src/app/features/stacks-transaction-request/transaction-error/error-messages.tsx +++ b/src/app/features/stacks-transaction-request/transaction-error/error-messages.tsx @@ -1,4 +1,4 @@ -import { memo } from 'react'; +import { memo, useState } from 'react'; import { Navigate } from 'react-router-dom'; import { STXTransferPayload, TransactionTypes } from '@stacks/connect'; @@ -8,9 +8,9 @@ import { RouteUrls } from '@shared/route-urls'; import { closeWindow } from '@shared/utils'; import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; -import { useDrawers } from '@app/common/hooks/use-drawers'; import { useScrollLock } from '@app/common/hooks/use-scroll-lock'; import { stacksValue } from '@app/common/stacks-utils'; +import { SwitchAccountDialog } from '@app/features/dialogs/switch-account-dialog/switch-account-dialog'; import { ErrorMessage } from '@app/features/stacks-transaction-request/transaction-error/error-message'; import { useCurrentStacksAccountBalances } from '@app/query/stacks/balance/stx-balance.hooks'; import { useCurrentNetworkState } from '@app/store/networks/networks.hooks'; @@ -24,7 +24,7 @@ interface InsufficientFundsActionButtonsProps { } function InsufficientFundsActionButtons({ eventName }: InsufficientFundsActionButtonsProps) { const analytics = useAnalytics(); - const { setIsShowingSwitchAccountsState } = useDrawers(); + const [isShowingSwitchAccount, setIsShowingSwitchAccount] = useState(false); const onGetStx = () => { void analytics.track(eventName); @@ -34,8 +34,12 @@ function InsufficientFundsActionButtons({ eventName }: InsufficientFundsActionBu return ( <> + setIsShowingSwitchAccount(false)} + /> - diff --git a/src/app/features/switch-account-drawer/components/create-account-action.tsx b/src/app/features/switch-account-drawer/components/create-account-action.tsx deleted file mode 100644 index c3de671b39b..00000000000 --- a/src/app/features/switch-account-drawer/components/create-account-action.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Flex } from 'leather-styles/jsx'; - -import { Button } from '@app/ui/components/button/button'; - -interface CreateAccountActionProps { - onCreateAccount(): void; -} -export function CreateAccountAction({ onCreateAccount }: CreateAccountActionProps) { - return ( - - - - ); -} diff --git a/src/app/features/switch-account-drawer/switch-account-drawer.tsx b/src/app/features/switch-account-drawer/switch-account-drawer.tsx deleted file mode 100644 index 765fdef4070..00000000000 --- a/src/app/features/switch-account-drawer/switch-account-drawer.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { memo } from 'react'; - -import { Box } from 'leather-styles/jsx'; - -import { useCreateAccount } from '@app/common/hooks/account/use-create-account'; -import { useWalletType } from '@app/common/use-wallet-type'; -import { ControlledDrawer } from '@app/components/drawer/controlled-drawer'; -import { useCurrentAccountIndex } from '@app/store/accounts/account'; -import { useFilteredBitcoinAccounts } from '@app/store/accounts/blockchain/bitcoin/bitcoin.ledger'; -import { useStacksAccounts } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; -import { useShowSwitchAccountsState } from '@app/store/ui/ui.hooks'; - -import { AccountListUnavailable } from './components/account-list-unavailable'; -import { CreateAccountAction } from './components/create-account-action'; -import { SwitchAccountList } from './components/switch-account-list'; - -export const SwitchAccountDrawer = memo(() => { - const [isShowing, setShowSwitchAccountsState] = useShowSwitchAccountsState(); - - const currentAccountIndex = useCurrentAccountIndex(); - const createAccount = useCreateAccount(); - const { whenWallet } = useWalletType(); - - const stacksAccounts = useStacksAccounts(); - const bitcoinAccounts = useFilteredBitcoinAccounts(); - const btcAddressesNum = bitcoinAccounts.length / 2; - const stacksAddressesNum = stacksAccounts.length; - - const onClose = () => setShowSwitchAccountsState(false); - - const onCreateAccount = () => { - createAccount(); - setShowSwitchAccountsState(false); - }; - - if (isShowing && stacksAddressesNum === 0 && btcAddressesNum === 0) { - return ; - } - - return isShowing ? ( - - - - {whenWallet({ - software: , - ledger: <>, - })} - - - ) : null; -}); diff --git a/src/app/features/theme-drawer/theme-drawer.tsx b/src/app/features/theme-drawer/theme-drawer.tsx deleted file mode 100644 index 52c68d3627f..00000000000 --- a/src/app/features/theme-drawer/theme-drawer.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { useNavigate } from 'react-router-dom'; - -import { useLocationState } from '@app/common/hooks/use-location-state'; -import { BaseDrawer } from '@app/components/drawer/base-drawer'; -import { useBackgroundLocationRedirect } from '@app/routes/hooks/use-background-location-redirect'; - -import { ThemeList } from './theme-list'; - -export function ThemesDrawer() { - useBackgroundLocationRedirect(); - const navigate = useNavigate(); - const backgroundLocation = useLocationState('backgroundLocation'); - return ( - navigate(backgroundLocation ?? '..')}> - - - ); -} diff --git a/src/app/features/theme-drawer/theme-list-item.tsx b/src/app/features/theme-drawer/theme-list-item.tsx deleted file mode 100644 index 6437bda0a9e..00000000000 --- a/src/app/features/theme-drawer/theme-list-item.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { useCallback } from 'react'; - -import { UserSelectedTheme, getThemeLabel } from '@app/common/theme-provider'; - -import { ThemeListItemLayout } from './theme-list-item-layout'; - -interface ThemeListItemProps { - theme: UserSelectedTheme; - onThemeSelected(theme: UserSelectedTheme): void; - isActive: boolean; -} -export function ThemeListItem({ theme, onThemeSelected, isActive }: ThemeListItemProps) { - const themeLabel = getThemeLabel(theme); - const itemSelectHandler = useCallback(() => { - onThemeSelected(theme); - }, [onThemeSelected, theme]); - - return ( - - ); -} diff --git a/src/app/pages/bitcoin-contract-list/bitcoin-contract-list.tsx b/src/app/pages/bitcoin-contract-list/bitcoin-contract-list.tsx index ba8eb71cd97..de64497e615 100644 --- a/src/app/pages/bitcoin-contract-list/bitcoin-contract-list.tsx +++ b/src/app/pages/bitcoin-contract-list/bitcoin-contract-list.tsx @@ -1,6 +1,6 @@ import { useState } from 'react'; -import { Flex, styled } from 'leather-styles/jsx'; +import { Flex, Stack, styled } from 'leather-styles/jsx'; import { BitcoinContractListItem, @@ -11,7 +11,6 @@ import { FullPageLoadingSpinner } from '@app/components/loading-spinner'; import { truncateMiddle } from '@app/ui/utils/truncate-middle'; import { BitcoinContractListItemLayout } from './components/bitcoin-contract-list-item-layout'; -import { BitcoinContractListLayout } from './components/bitcoin-contract-list-layout'; export function BitcoinContractList() { const { getAllActiveBitcoinContracts } = useBitcoinContracts(); @@ -36,7 +35,7 @@ export function BitcoinContractList() { if (isLoading) return ; return ( - + {bitcoinContracts.length === 0 || isError ? ( @@ -58,6 +57,6 @@ export function BitcoinContractList() { ); }) )} - + ); } diff --git a/src/app/pages/bitcoin-contract-list/components/bitcoin-contract-list-item-layout.tsx b/src/app/pages/bitcoin-contract-list/components/bitcoin-contract-list-item-layout.tsx index 12fb05fa080..3d5d9161ed9 100644 --- a/src/app/pages/bitcoin-contract-list/components/bitcoin-contract-list-item-layout.tsx +++ b/src/app/pages/bitcoin-contract-list/components/bitcoin-contract-list-item-layout.tsx @@ -38,7 +38,7 @@ export function BitcoinContractListItemLayout({ return ( handleOpenTxLink({ txid, diff --git a/src/app/pages/bitcoin-contract-list/components/bitcoin-contract-list-layout.tsx b/src/app/pages/bitcoin-contract-list/components/bitcoin-contract-list-layout.tsx deleted file mode 100644 index 3074f22f036..00000000000 --- a/src/app/pages/bitcoin-contract-list/components/bitcoin-contract-list-layout.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { ReactNode } from 'react'; -import { useNavigate } from 'react-router-dom'; - -import { Stack } from 'leather-styles/jsx'; - -import { RouteUrls } from '@shared/route-urls'; - -import { useRouteHeader } from '@app/common/hooks/use-route-header'; -import { Header } from '@app/components/header'; - -interface BitcoinContractListProps { - children: ReactNode; -} -export function BitcoinContractListLayout({ children }: BitcoinContractListProps) { - const navigate = useNavigate(); - useRouteHeader(
navigate(RouteUrls.Home)} />); - return ( - - {children} - - ); -} diff --git a/src/app/pages/bitcoin-contract-request/bitcoin-contract-request.tsx b/src/app/pages/bitcoin-contract-request/bitcoin-contract-request.tsx index 46150148e84..9b8904170f2 100644 --- a/src/app/pages/bitcoin-contract-request/bitcoin-contract-request.tsx +++ b/src/app/pages/bitcoin-contract-request/bitcoin-contract-request.tsx @@ -13,11 +13,11 @@ import { import { useOnMount } from '@app/common/hooks/use-on-mount'; import { initialSearchParams } from '@app/common/initial-search-params'; import { useCurrentAccountNativeSegwitSigner } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks'; +import { PopupCard } from '@app/ui/components/containers/popup/popup-card'; import { BitcoinContractOfferDetailsSimple } from './components/bitcoin-contract-offer/bitcoin-contract-offer-details'; import { BitcoinContractRequestActions } from './components/bitcoin-contract-request-actions'; import { BitcoinContractRequestHeader } from './components/bitcoin-contract-request-header'; -import { BitcoinContractRequestLayout } from './components/bitcoin-contract-request-layout'; import { BitcoinContractRequestWarningLabel } from './components/bitcoin-contract-request-warning-label'; export function BitcoinContractRequest() { @@ -103,7 +103,7 @@ export function BitcoinContractRequest() { return ( <> {!isLoading && bitcoinAddress && bitcoinContractOfferDetails && ( - + - + @@ -130,7 +130,7 @@ export function BitcoinContractRequest() { bitcoinAddress={bitcoinAddress} bitcoinContractOffer={bitcoinContractOfferDetails.simplifiedBitcoinContract} /> - + )} ); diff --git a/src/app/pages/bitcoin-contract-request/components/bitcoin-contract-request-actions.tsx b/src/app/pages/bitcoin-contract-request/components/bitcoin-contract-request-actions.tsx index 10a34eafb81..05e86cffa8c 100644 --- a/src/app/pages/bitcoin-contract-request/components/bitcoin-contract-request-actions.tsx +++ b/src/app/pages/bitcoin-contract-request/components/bitcoin-contract-request-actions.tsx @@ -1,8 +1,8 @@ import { BitcoinContractRequestSelectors } from '@tests/selectors/bitcoin-contract-request.selectors'; -import { Box, HStack } from 'leather-styles/jsx'; import { useBtcAssetBalance } from '@app/common/hooks/balance/btc/use-btc-balance'; import { Button } from '@app/ui/components/button/button'; +import { Footer } from '@app/ui/components/containers/footers/footer'; interface BitcoinContractRequestActionsProps { isLoading: boolean; @@ -22,35 +22,24 @@ export function BitcoinContractRequestActions({ const canAccept = btcAvailableAssetBalance.balance.amount.isGreaterThan(requiredAmount); return ( - - - - - - +
+ + +
); } diff --git a/src/app/pages/bitcoin-contract-request/components/bitcoin-contract-request-layout.tsx b/src/app/pages/bitcoin-contract-request/components/bitcoin-contract-request-layout.tsx deleted file mode 100644 index 171c52142ab..00000000000 --- a/src/app/pages/bitcoin-contract-request/components/bitcoin-contract-request-layout.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { Stack } from 'leather-styles/jsx'; - -interface BitcoinContractRequestLayoutProps { - children: React.ReactNode; -} -export function BitcoinContractRequestLayout({ children }: BitcoinContractRequestLayoutProps) { - return ( - - {children} - - ); -} diff --git a/src/app/pages/choose-account/choose-account.tsx b/src/app/pages/choose-account/choose-account.tsx index 90f75fe195c..2f36a4050ad 100644 --- a/src/app/pages/choose-account/choose-account.tsx +++ b/src/app/pages/choose-account/choose-account.tsx @@ -7,7 +7,6 @@ import { closeWindow } from '@shared/utils'; import { useCancelAuthRequest } from '@app/common/authentication/use-cancel-auth-request'; import { useAppDetails } from '@app/common/hooks/auth/use-app-details'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; import { RequesterFlag } from '@app/components/requester-flag'; import { ChooseAccountsList } from '@app/pages/choose-account/components/accounts'; import { useOnOriginTabClose } from '@app/routes/hooks/use-on-tab-closed'; @@ -18,7 +17,6 @@ export const ChooseAccount = memo(() => { const cancelAuthentication = useCancelAuthRequest(); - useRouteHeader(<>); useOnOriginTabClose(() => closeWindow()); const handleUnmount = async () => cancelAuthentication(); diff --git a/src/app/pages/choose-account/components/accounts.tsx b/src/app/pages/choose-account/components/accounts.tsx index c7b957d5cd1..432f58fe5d9 100644 --- a/src/app/pages/choose-account/components/accounts.tsx +++ b/src/app/pages/choose-account/components/accounts.tsx @@ -13,12 +13,12 @@ import { useWalletType } from '@app/common/use-wallet-type'; import { slugify } from '@app/common/utils'; import { AccountTotalBalance } from '@app/components/account-total-balance'; import { AcccountAddresses } from '@app/components/account/account-addresses'; -import { AccountAvatar } from '@app/components/account/account-avatar'; import { AccountListItemLayout } from '@app/components/account/account-list-item.layout'; import { usePressable } from '@app/components/item-hover'; import { useNativeSegwitAccountIndexAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks'; import { useStacksAccounts } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; import { StacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.models'; +import { AccountAvatar } from '@app/ui/components/account/account-avatar/account-avatar'; import { PlusIcon } from '@app/ui/icons/plus-icon'; interface AccountTitlePlaceholderProps { diff --git a/src/app/pages/fund/choose-asset-to-fund/choose-asset-to-fund.tsx b/src/app/pages/fund/choose-asset-to-fund/choose-asset-to-fund.tsx index 3745bd094c2..6e7e09e096e 100644 --- a/src/app/pages/fund/choose-asset-to-fund/choose-asset-to-fund.tsx +++ b/src/app/pages/fund/choose-asset-to-fund/choose-asset-to-fund.tsx @@ -6,12 +6,10 @@ import { RouteUrls } from '@shared/route-urls'; import { isDefined } from '@shared/utils'; import { useStxCryptoCurrencyAssetBalance } from '@app/common/hooks/balance/stx/use-stx-crypto-currency-asset-balance'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; import { useWalletType } from '@app/common/use-wallet-type'; import { ChooseAssetContainer } from '@app/components/crypto-assets/choose-crypto-asset/choose-asset-container'; import { ChooseCryptoAssetLayout } from '@app/components/crypto-assets/choose-crypto-asset/choose-crypto-asset.layout'; import { CryptoAssetList } from '@app/components/crypto-assets/choose-crypto-asset/crypto-asset-list'; -import { ModalHeader } from '@app/components/modal-header'; import { useCheckLedgerBlockchainAvailable } from '@app/store/accounts/blockchain/utils'; export function ChooseCryptoAssetToFund() { @@ -33,8 +31,6 @@ export function ChooseCryptoAssetToFund() { [stxCryptoCurrencyAssetBalance, checkBlockchainAvailable, whenWallet] ); - useRouteHeader( navigate(RouteUrls.Home)} title=" " />); - const navigateToSendForm = useCallback( (cryptoAssetBalance: AllTransferableCryptoAssetBalances) => { const { asset } = cryptoAssetBalance; diff --git a/src/app/pages/fund/components/fund-account-tile.tsx b/src/app/pages/fund/components/fund-account-tile.tsx index 2396a3a7552..fb74e6820d5 100644 --- a/src/app/pages/fund/components/fund-account-tile.tsx +++ b/src/app/pages/fund/components/fund-account-tile.tsx @@ -25,7 +25,7 @@ export function FundAccountTile(props: FundAccountTileProps) { cursor: 'pointer', }} border="default" - backgroundColor="ink.background-primary" + bg="ink.background-primary" borderRadius="xs" boxShadow="0px 1px 2px rgba(0, 0, 0, 0.04)" data-testid={testId} diff --git a/src/app/pages/fund/components/fund.layout.tsx b/src/app/pages/fund/components/fund.layout.tsx index 3e5e1434c80..80b2a63fa68 100644 --- a/src/app/pages/fund/components/fund.layout.tsx +++ b/src/app/pages/fund/components/fund.layout.tsx @@ -1,4 +1,4 @@ -import { Flex, Stack, styled } from 'leather-styles/jsx'; +import { Stack, styled } from 'leather-styles/jsx'; import { CryptoCurrencies } from '@shared/models/currencies.model'; @@ -23,40 +23,32 @@ export function FundLayout({ symbol, children }: FundLayoutProps) { const name = nameMap[symbol].name; const nameAbbr = nameMap[symbol].symbol; return ( - - - - Let's get funds into your wallet - + Let's get BTC
+ into your wallet + - - Choose an exchange to fund your account with {name} ({nameAbbr}) or deposit from - elsewhere. Exchanges with “Fast checkout” make it easier to purchase {nameAbbr} for direct - deposit into your wallet with a credit card. - -
+ + Choose an exchange to fund your account with {name} ({nameAbbr}) or deposit from elsewhere. + Exchanges with “Fast checkout” make it easier to purchase {nameAbbr} for direct deposit into + your wallet with a credit card. + {children} -
+ ); } diff --git a/src/app/pages/fund/fiat-providers-list.tsx b/src/app/pages/fund/fiat-providers-list.tsx index 67c7680a46e..446abe09cf3 100644 --- a/src/app/pages/fund/fiat-providers-list.tsx +++ b/src/app/pages/fund/fiat-providers-list.tsx @@ -48,22 +48,10 @@ export function FiatProvidersList(props: FiatProvidersProps) { return ( navigate(RouteUrls.FundChooseCurrency)} title=" " />); - if (!address || !balance) return ; return ( <> diff --git a/src/app/pages/home/components/account-actions.tsx b/src/app/pages/home/components/account-actions.tsx index 02ac19609f8..11440c54378 100644 --- a/src/app/pages/home/components/account-actions.tsx +++ b/src/app/pages/home/components/account-actions.tsx @@ -2,7 +2,7 @@ import { useLocation, useNavigate } from 'react-router-dom'; import { ChainID } from '@stacks/transactions'; import { HomePageSelectors } from '@tests/selectors/home.selectors'; -import { Flex, FlexProps } from 'leather-styles/jsx'; +import { Flex } from 'leather-styles/jsx'; import { RouteUrls } from '@shared/route-urls'; @@ -11,12 +11,12 @@ import { useConfigBitcoinEnabled } from '@app/query/common/remote-config/remote- import { useCurrentAccountNativeSegwitIndexZeroSignerNullable } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks'; import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; import { useCurrentNetwork } from '@app/store/networks/networks.selectors'; +import { ActionButton } from '@app/ui/components/account/action-button'; import { CreditCardIcon, InboxIcon, SwapIcon } from '@app/ui/icons'; -import { ActionButton } from './action-button'; import { SendButton } from './send-button'; -export function AccountActions(props: FlexProps) { +export function AccountActions() { const navigate = useNavigate(); const location = useLocation(); const isBitcoinEnabled = useConfigBitcoinEnabled(); @@ -30,7 +30,7 @@ export function AccountActions(props: FlexProps) { : `${RouteUrls.Home}${RouteUrls.ReceiveStx}`; return ( - + { - const currentAccount = useCurrentStacksAccount(); - const btcAddress = useCurrentAccountNativeSegwitAddressIndexZero(); - - if (!currentAccount) return null; - return ( - - - - - - - - - - ); -}); diff --git a/src/app/pages/home/components/account-info-card.tsx b/src/app/pages/home/components/account-info-card.tsx deleted file mode 100644 index 9a0e2ff6059..00000000000 --- a/src/app/pages/home/components/account-info-card.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { SettingsSelectors } from '@tests/selectors/settings.selectors'; -import { Box, Divider, Flex, styled } from 'leather-styles/jsx'; - -import { useCurrentAccountDisplayName } from '@app/common/hooks/account/use-account-names'; -import { useTotalBalance } from '@app/common/hooks/balance/use-total-balance'; -import { useDrawers } from '@app/common/hooks/use-drawers'; -import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks'; -import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; -import { Link } from '@app/ui/components/link/link'; -import { ChevronDownIcon } from '@app/ui/icons/chevron-down-icon'; - -import { AccountActions } from './account-actions'; - -export function AccountInfoCard() { - const name = useCurrentAccountDisplayName(); - - const account = useCurrentStacksAccount(); - const btcAddress = useCurrentAccountNativeSegwitAddressIndexZero(); - const totalBalance = useTotalBalance({ btcAddress, stxAddress: account?.address || '' }); - - const { setIsShowingSwitchAccountsState } = useDrawers(); - - return ( - - setIsShowingSwitchAccountsState(true)} - > - - - {name} - - - - - - - - - {totalBalance?.totalUsdBalance} - - - - - - - ); -} diff --git a/src/app/pages/home/components/home-tabs.tsx b/src/app/pages/home/components/home-tabs.tsx index f19f8ba83e8..23b1c1a8ae0 100644 --- a/src/app/pages/home/components/home-tabs.tsx +++ b/src/app/pages/home/components/home-tabs.tsx @@ -11,7 +11,7 @@ import { Tabs } from '@app/ui/components/tabs/tabs'; interface HomeTabsProps { children: React.ReactNode; } -// TODO #4013: Abstract this to generic RouteTab once choose-fee-tab updated + export function HomeTabs({ children }: HomeTabsProps) { const navigate = useNavigate(); const location = useLocation(); @@ -23,13 +23,15 @@ export function HomeTabs({ children }: HomeTabsProps) { Assets - + Activity }> - {children} + + {children} + ); diff --git a/src/app/pages/home/components/home.layout.tsx b/src/app/pages/home/components/home.layout.tsx deleted file mode 100644 index cb10533830d..00000000000 --- a/src/app/pages/home/components/home.layout.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react'; - -import { HomePageSelectors } from '@tests/selectors/home.selectors'; -import { Stack } from 'leather-styles/jsx'; - -import { AccountInfoCard } from './account-info-card'; - -type HomeLayoutProps = Record<'currentAccount' | 'children', React.ReactNode>; -export function HomeLayout({ children }: HomeLayoutProps) { - return ( - - - - {children} - - - ); -} diff --git a/src/app/pages/home/components/send-button.tsx b/src/app/pages/home/components/send-button.tsx index 76fc5aa68d0..b3a9916735b 100644 --- a/src/app/pages/home/components/send-button.tsx +++ b/src/app/pages/home/components/send-button.tsx @@ -13,10 +13,9 @@ import { useTransferableStacksFungibleTokenAssetBalances, } from '@app/query/stacks/balance/stacks-ft-balances.hooks'; import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; +import { ActionButton } from '@app/ui/components/account/action-button'; import { SendIcon } from '@app/ui/icons'; -import { ActionButton } from './action-button'; - function SendButtonSuspense() { const navigate = useNavigate(); const { whenWallet } = useWalletType(); @@ -34,10 +33,10 @@ function SendButtonSuspense() { whenWallet({ ledger: () => whenPageMode({ - full: () => navigate(RouteUrls.SendCryptoAsset, { state: { hasHeaderTitle: true } }), + full: () => navigate(RouteUrls.SendCryptoAsset), popup: () => openIndexPageInNewTab(RouteUrls.SendCryptoAsset), })(), - software: () => navigate(RouteUrls.SendCryptoAsset, { state: { hasHeaderTitle: true } }), + software: () => navigate(RouteUrls.SendCryptoAsset), })() } disabled={isDisabled} diff --git a/src/app/pages/home/home.tsx b/src/app/pages/home/home.tsx index d6187512d63..2c19573e619 100644 --- a/src/app/pages/home/home.tsx +++ b/src/app/pages/home/home.tsx @@ -1,45 +1,64 @@ +import { useState } from 'react'; import { Route, useNavigate } from 'react-router-dom'; import { RouteUrls } from '@shared/route-urls'; +import { useCurrentAccountDisplayName } from '@app/common/hooks/account/use-account-names'; import { useOnboardingState } from '@app/common/hooks/auth/use-onboarding-state'; +import { useTotalBalance } from '@app/common/hooks/balance/use-total-balance'; import { useOnMount } from '@app/common/hooks/use-on-mount'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; -import { Header } from '@app/components/header'; import { ActivityList } from '@app/features/activity-list/activity-list'; import { AssetsList } from '@app/features/asset-list/asset-list'; +import { SwitchAccountDialog } from '@app/features/dialogs/switch-account-dialog/switch-account-dialog'; import { FeedbackButton } from '@app/features/feedback-button/feedback-button'; -import { InAppMessages } from '@app/features/hiro-messages/in-app-messages'; import { homePageModalRoutes } from '@app/routes/app-routes'; import { ModalBackgroundWrapper } from '@app/routes/components/modal-background-wrapper'; +import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks'; +import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; +import { AccountCard } from '@app/ui/components/account/account.card'; +import { HomeLayout } from '@app/ui/pages/home.layout'; -import { CurrentAccount } from './components/account-area'; +import { AccountActions } from './components/account-actions'; import { HomeTabs } from './components/home-tabs'; -import { HomeLayout } from './components/home.layout'; export function Home() { + const [isShowingSwitchAccount, setIsShowingSwitchAccount] = useState(false); const { decodedAuthRequest } = useOnboardingState(); const navigate = useNavigate(); + const name = useCurrentAccountDisplayName(); - useRouteHeader( - <> - -
- - ); + const account = useCurrentStacksAccount(); + const btcAddress = useCurrentAccountNativeSegwitAddressIndexZero(); + const totalBalance = useTotalBalance({ btcAddress, stxAddress: account?.address || '' }); useOnMount(() => { if (decodedAuthRequest) navigate(RouteUrls.ChooseAccount); }); return ( - }> + setIsShowingSwitchAccount(false)} + /> + } + toggleSwitchAccount={() => setIsShowingSwitchAccount(!isShowingSwitchAccount)} + > + + + } + > } /> - }> + }> {homePageModalRoutes} {homePageModalRoutes} diff --git a/src/app/pages/onboarding/allow-diagnostics/allow-diagnostics-layout.tsx b/src/app/pages/onboarding/allow-diagnostics/allow-diagnostics-layout.tsx index ccb2bc099aa..0be6e412648 100644 --- a/src/app/pages/onboarding/allow-diagnostics/allow-diagnostics-layout.tsx +++ b/src/app/pages/onboarding/allow-diagnostics/allow-diagnostics-layout.tsx @@ -1,10 +1,10 @@ -import { Dialog } from '@radix-ui/themes'; import { OnboardingSelectors } from '@tests/selectors/onboarding.selectors'; -import { css } from 'leather-styles/css'; -import { Box, Flex, HStack, Stack, styled } from 'leather-styles/jsx'; +import { Box, Flex, Stack, styled } from 'leather-styles/jsx'; import { Button } from '@app/ui/components/button/button'; -import { CheckmarkIcon } from '@app/ui/icons/checkmark-icon'; +import { Dialog } from '@app/ui/components/containers/dialog/dialog'; +import { Footer } from '@app/ui/components/containers/footers/footer'; +import { CheckmarkIcon } from '@app/ui/icons/'; import { LogomarkIcon } from '@app/ui/icons/logomark-icon'; interface ReasonToAllowDiagnosticsProps { @@ -25,51 +25,53 @@ interface AllowDiagnosticsLayoutProps { onUserAllowDiagnostics(): void; onUserDenyDiagnostics(): void; } -export function AllowDiagnosticsLayout(props: AllowDiagnosticsLayoutProps) { - const { onUserAllowDiagnostics, onUserDenyDiagnostics } = props; +export function AllowDiagnosticsLayout({ + onUserAllowDiagnostics, + onUserDenyDiagnostics, +}: AllowDiagnosticsLayoutProps) { return ( - - - - - Help us improve - - + null} + isShowing + footer={ +
+ + + + +
+ } + > + + + + + Help us improve + Leather would like to gather deidentified service usage data to help improve the experience of the wallet. - + - - - - - -
-
+ + ); } diff --git a/src/app/pages/onboarding/allow-diagnostics/allow-diagnostics.tsx b/src/app/pages/onboarding/allow-diagnostics/allow-diagnostics.tsx index a7c44eab07f..4d1dd6e5263 100644 --- a/src/app/pages/onboarding/allow-diagnostics/allow-diagnostics.tsx +++ b/src/app/pages/onboarding/allow-diagnostics/allow-diagnostics.tsx @@ -5,8 +5,6 @@ import { useLocation, useNavigate } from 'react-router-dom'; import { RouteUrls } from '@shared/route-urls'; import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; -import { Header } from '@app/components/header'; import { settingsActions } from '@app/store/settings/settings.actions'; import { AllowDiagnosticsLayout } from './allow-diagnostics-layout'; @@ -19,8 +17,6 @@ export function AllowDiagnosticsModal() { useEffect(() => void analytics.page('view', `${pathname}`), [analytics, pathname]); - useRouteHeader(
); - const setDiagnosticsPermissionsAndGoToOnboarding = useCallback( (areDiagnosticsAllowed: boolean) => { dispatch(settingsActions.setHasAllowedAnalytics(areDiagnosticsAllowed)); diff --git a/src/app/pages/onboarding/back-up-secret-key/back-up-secret-key.tsx b/src/app/pages/onboarding/back-up-secret-key/back-up-secret-key.tsx index 210ab4f6ab0..8721ef746e3 100644 --- a/src/app/pages/onboarding/back-up-secret-key/back-up-secret-key.tsx +++ b/src/app/pages/onboarding/back-up-secret-key/back-up-secret-key.tsx @@ -1,22 +1,19 @@ import { memo, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; +import { HStack, Stack, styled } from 'leather-styles/jsx'; + import { RouteUrls } from '@shared/route-urls'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; -import { Header } from '@app/components/header'; -import { TwoColumnLayout } from '@app/components/secret-key/two-column.layout'; -import { SecretKeyDisplayer } from '@app/features/secret-key-displayer/secret-key-displayer'; +import { SecretKey } from '@app/features/secret-key-displayer/secret-key-displayer'; import { useDefaultWalletSecretKey } from '@app/store/in-memory-key/in-memory-key.selectors'; - -import { BackUpSecretKeyContent } from './components/back-up-secret-key.content'; +import { EyeSlashIcon, KeyIcon, LockIcon } from '@app/ui/icons/'; +import { TwoColumnLayout } from '@app/ui/pages/two-column.layout'; export const BackUpSecretKeyPage = memo(() => { const secretKey = useDefaultWalletSecretKey(); const navigate = useNavigate(); - useRouteHeader(
); - useEffect(() => { if (!secretKey) navigate(RouteUrls.Onboarding); }, [navigate, secretKey]); @@ -25,8 +22,37 @@ export const BackUpSecretKeyPage = memo(() => { return ( } - rightColumn={} - /> + title={<>Back up your Secret Key} + content={ + <> + You'll need it to access your wallet on a new device, or this one if you lose your + password — so back it up somewhere safe! + + } + action={ + + + + + Your Secret Key gives
access to your wallet +
+
+ + + + Never share your
Secret Key with anyone +
+
+ + + + Store it somewhere
100% private and secure +
+
+
+ } + > + +
); }); diff --git a/src/app/pages/onboarding/back-up-secret-key/components/back-up-secret-key.content.tsx b/src/app/pages/onboarding/back-up-secret-key/components/back-up-secret-key.content.tsx deleted file mode 100644 index 050fd314f75..00000000000 --- a/src/app/pages/onboarding/back-up-secret-key/components/back-up-secret-key.content.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { HStack, Stack, styled } from 'leather-styles/jsx'; - -import { KeyIcon } from '@app/ui/icons'; -import { EyeSlashIcon } from '@app/ui/icons/eye-slash-icon'; -import { LockIcon } from '@app/ui/icons/lock-icon'; - -export function BackUpSecretKeyContent(): React.JSX.Element { - return ( - <> - - Back up your
Secret Key -
- - Here's your Secret Key: 24 words that give you access to your new wallet. - - - You'll need it to access your wallet on a new device, or this one if you lose your password - — so back it up somewhere safe! - - - - - - Your Secret Key gives access to your wallet - - - - Never share your Secret Key with anyone - - - - Store it somewhere 100% private and secure - - - - ); -} diff --git a/src/app/pages/onboarding/set-password/components/password-bars.tsx b/src/app/pages/onboarding/set-password/components/password-bars.tsx index afa5cc44e98..1aabe5f3610 100644 --- a/src/app/pages/onboarding/set-password/components/password-bars.tsx +++ b/src/app/pages/onboarding/set-password/components/password-bars.tsx @@ -6,21 +6,19 @@ interface PasswordStrengthBarsProps { export function PasswordStrengthBars({ bars }: PasswordStrengthBarsProps) { return ( - {bars.map((bar: string, index: number) => { - return ( - - ); - })} + {bars.map((bar: string, index: number) => ( + + ))} ); } diff --git a/src/app/pages/onboarding/set-password/set-password.tsx b/src/app/pages/onboarding/set-password/set-password.tsx index b581478f9b9..dcc6e3efc09 100644 --- a/src/app/pages/onboarding/set-password/set-password.tsx +++ b/src/app/pages/onboarding/set-password/set-password.tsx @@ -3,7 +3,6 @@ import { useNavigate } from 'react-router-dom'; import { OnboardingSelectors } from '@tests/selectors/onboarding.selectors'; import { Form, Formik } from 'formik'; -import { styled } from 'leather-styles/jsx'; import { debounce } from 'ts-debounce'; import * as yup from 'yup'; @@ -14,16 +13,14 @@ import { useFinishAuthRequest } from '@app/common/authentication/use-finish-auth import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; import { useOnboardingState } from '@app/common/hooks/auth/use-onboarding-state'; import { useKeyActions } from '@app/common/hooks/use-key-actions'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; import { blankPasswordValidation, validatePassword, } from '@app/common/validation/validate-password'; -import { Header } from '@app/components/header'; -import { TwoColumnLayout } from '@app/components/secret-key/two-column.layout'; import { OnboardingGate } from '@app/routes/onboarding-gate'; import { useStacksAccounts } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; import { Button } from '@app/ui/components/button/button'; +import { TwoColumnLayout } from '@app/ui/pages/two-column.layout'; import { PasswordField } from './components/password-field'; @@ -53,8 +50,6 @@ function SetPasswordPage() { const { decodedAuthRequest } = useOnboardingState(); const analytics = useAnalytics(); - useRouteHeader(
navigate(-1)} />); - useEffect(() => { void analytics.page('view', '/set-password'); }, [analytics]); @@ -125,48 +120,33 @@ function SetPasswordPage() { {({ dirty, isSubmitting, isValid }) => (
- - Set a password - - - Your password protects your Secret Key on this device only. - - - You'll need just your Secret Key to access your wallet on another device, or this - one if you lose your password. - + Set a
+ password } - rightColumn={ + content={ <> - - Your password - - - + Your password protects your Secret Key on this device only. To access your wallet on + another device, you'll need just your Secret Key. } - /> + > + <> + + + +
)} diff --git a/src/app/pages/onboarding/sign-in/components/sign-in.content.tsx b/src/app/pages/onboarding/sign-in/components/sign-in.content.tsx deleted file mode 100644 index 497c0bd6290..00000000000 --- a/src/app/pages/onboarding/sign-in/components/sign-in.content.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { styled } from 'leather-styles/jsx'; - -import { Link } from '@app/ui/components/link/link'; - -export function SignInContent({ - onClick, - twentyFourWordMode, -}: { - onClick(): void; - twentyFourWordMode: boolean; -}): React.JSX.Element { - return ( - <> - - Sign in
with your
- Secret Key -
- - Speed things up by pasting your entire Secret Key in one go. - - - {twentyFourWordMode ? 'Have a 12-word Secret Key?' : 'Use 24 word Secret Key'} - - - ); -} diff --git a/src/app/pages/onboarding/sign-in/mnemonic-form.tsx b/src/app/pages/onboarding/sign-in/mnemonic-form.tsx index e0c2f0b1060..2a9e327e497 100644 --- a/src/app/pages/onboarding/sign-in/mnemonic-form.tsx +++ b/src/app/pages/onboarding/sign-in/mnemonic-form.tsx @@ -1,22 +1,21 @@ import { OnboardingSelectors } from '@tests/selectors/onboarding.selectors'; import { Form, Formik } from 'formik'; -import { Flex, styled } from 'leather-styles/jsx'; +import { Stack } from 'leather-styles/jsx'; import { isEmpty } from '@shared/utils'; import { createNullArrayOfLength } from '@app/common/utils'; import { ErrorLabel } from '@app/components/error-label'; -import { SecretKeyGrid } from '@app/components/secret-key/secret-key-grid'; import { useSignIn } from '@app/pages/onboarding/sign-in/hooks/use-sign-in'; import { Button } from '@app/ui/components/button/button'; - -import { MnemonicWordInput } from '../../../components/secret-key/mnemonic-key/mnemonic-word-input'; +import { MnemonicWordInput } from '@app/ui/components/secret-key/mnemonic-key/mnemonic-word-input'; import { getMnemonicErrorFields, getMnemonicErrorMessage, hasMnemonicFormValues, -} from '../../../components/secret-key/mnemonic-key/utils/error-handling'; -import { validationSchema } from '../../../components/secret-key/mnemonic-key/utils/validation'; +} from '@app/ui/components/secret-key/mnemonic-key/utils/error-handling'; +import { validationSchema } from '@app/ui/components/secret-key/mnemonic-key/utils/validation'; +import { SecretKeyGrid } from '@app/ui/components/secret-key/secret-key-grid'; interface MnemonicFormProps { mnemonic: (string | null)[]; @@ -69,24 +68,21 @@ export function MnemonicForm({ mnemonic, setMnemonic, twentyFourWordMode }: Mnem return (
- - Your Secret Key - - - {mnemonicFieldArray.map((_, i) => ( - { - (document.activeElement as HTMLInputElement).blur(); - updateEntireKey(key, setFieldValue); - }} - onUpdateWord={w => mnemonicWordUpdate(i, w)} - /> - ))} - - + + + {mnemonicFieldArray.map((_, i) => ( + { + (document.activeElement as HTMLInputElement).blur(); + updateEntireKey(key, setFieldValue); + }} + onUpdateWord={w => mnemonicWordUpdate(i, w)} + /> + ))} + {(showMnemonicErrors || error) && ( {showMnemonicErrors ? mnemonicErrorMessage : error} @@ -100,6 +96,7 @@ export function MnemonicForm({ mnemonic, setMnemonic, twentyFourWordMode }: Mnem aria-busy={isLoading} width="100%" type="submit" + variant="solid" onClick={e => { e.preventDefault(); return handleSubmit(); @@ -107,7 +104,7 @@ export function MnemonicForm({ mnemonic, setMnemonic, twentyFourWordMode }: Mnem > Continue - +
); }} diff --git a/src/app/pages/onboarding/sign-in/sign-in.tsx b/src/app/pages/onboarding/sign-in/sign-in.tsx index faad25e2dcb..45083dfd0e6 100644 --- a/src/app/pages/onboarding/sign-in/sign-in.tsx +++ b/src/app/pages/onboarding/sign-in/sign-in.tsx @@ -1,24 +1,14 @@ import { useEffect, useState } from 'react'; -import { useNavigate } from 'react-router-dom'; -import { RouteUrls } from '@shared/route-urls'; - -import { useRouteHeader } from '@app/common/hooks/use-route-header'; import { createNullArrayOfLength } from '@app/common/utils'; -import { Header } from '@app/components/header'; -import { TwoColumnLayout } from '@app/components/secret-key/two-column.layout'; import { MnemonicForm } from '@app/pages/onboarding/sign-in/mnemonic-form'; - -import { SignInContent } from './components/sign-in.content'; +import { Link } from '@app/ui/components/link/link'; +import { TwoColumnLayout } from '@app/ui/pages/two-column.layout'; export function SignIn() { - const navigate = useNavigate(); - const [twentyFourWordMode, setTwentyFourWordMode] = useState(true); const [mnemonic, setMnemonic] = useState<(string | null)[]>([]); - useRouteHeader(
navigate(RouteUrls.Onboarding)} hideActions />); - useEffect(() => { const emptyMnemonicArray = twentyFourWordMode ? createNullArrayOfLength(24) @@ -27,22 +17,29 @@ export function SignIn() { }, [twentyFourWordMode]); return ( - <> - setTwentyFourWordMode(!twentyFourWordMode)} - twentyFourWordMode={twentyFourWordMode} - /> - } - rightColumn={ - - } + + Sign in
with your
Secret Key + + } + content={<>Speed things up by pasting your entire Secret Key in one go.} + action={ + setTwentyFourWordMode(!twentyFourWordMode)} + textStyle="label.03" + width="fit-content" + variant="text" + > + {twentyFourWordMode ? 'Have a 12-word Secret Key?' : 'Use 24 word Secret Key'} + + } + > + - +
); } diff --git a/src/app/pages/onboarding/welcome/welcome.layout.tsx b/src/app/pages/onboarding/welcome/welcome.layout.tsx deleted file mode 100644 index 64cee800550..00000000000 --- a/src/app/pages/onboarding/welcome/welcome.layout.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import { OnboardingSelectors } from '@tests/selectors/onboarding.selectors'; -import { Box, Flex, styled } from 'leather-styles/jsx'; - -import { useViewportMinWidth } from '@app/common/hooks/use-media-query'; -import { Button } from '@app/ui/components/button/button'; -import { Link } from '@app/ui/components/link/link'; -import { LettermarkIcon } from '@app/ui/icons/lettermark-icon'; -import { LogomarkIcon } from '@app/ui/icons/logomark-icon'; - -interface WelcomeLayoutProps { - tagline: React.ReactNode; - subheader: React.ReactNode; - isGeneratingWallet: boolean; - onSelectConnectLedger(): void; - onStartOnboarding(): void; - onRestoreWallet(): void; -} -export function WelcomeLayout({ - tagline, - subheader, - isGeneratingWallet, - onStartOnboarding, - onSelectConnectLedger, - onRestoreWallet, -}: WelcomeLayoutProps): React.JSX.Element { - const isAtleastBreakpointMd = useViewportMinWidth('md'); - - return ( - - - - - - {tagline} - - - {subheader} - - - - - - - - Use existing key - - - - Use Ledger - - - - - - - - - - - ); -} diff --git a/src/app/pages/onboarding/welcome/welcome.tsx b/src/app/pages/onboarding/welcome/welcome.tsx index b513e63bcaf..ae3a1d54166 100644 --- a/src/app/pages/onboarding/welcome/welcome.tsx +++ b/src/app/pages/onboarding/welcome/welcome.tsx @@ -7,12 +7,10 @@ import { closeWindow } from '@shared/utils'; import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; import { useOnboardingState } from '@app/common/hooks/auth/use-onboarding-state'; import { useKeyActions } from '@app/common/hooks/use-key-actions'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; import { doesBrowserSupportWebUsbApi, isPopupMode, whenPageMode } from '@app/common/utils'; import { openIndexPageInNewTab } from '@app/common/utils/open-in-new-tab'; import { useHasUserRespondedToAnalyticsConsent } from '@app/store/settings/settings.selectors'; - -import { WelcomeLayout } from './welcome.layout'; +import { WelcomeLayout } from '@app/ui/pages/welcome.layout'; export function WelcomePage() { const hasResponded = useHasUserRespondedToAnalyticsConsent(); @@ -23,7 +21,6 @@ export function WelcomePage() { const [isGeneratingWallet, setIsGeneratingWallet] = useState(false); - useRouteHeader(<>); const startOnboarding = useCallback(async () => { if (isPopupMode()) { openIndexPageInNewTab(RouteUrls.Onboarding); @@ -79,8 +76,6 @@ export function WelcomePage() { return ( <> startOnboarding()} diff --git a/src/app/pages/receive/components/receive-collectibles.tsx b/src/app/pages/receive/components/receive-collectibles.tsx new file mode 100644 index 00000000000..fd0999e859f --- /dev/null +++ b/src/app/pages/receive/components/receive-collectibles.tsx @@ -0,0 +1,55 @@ +import { HomePageSelectors } from '@tests/selectors/home.selectors'; +import { css } from 'leather-styles/css'; +import { Stack } from 'leather-styles/jsx'; + +import { copyToClipboard } from '@app/common/utils/copy-to-clipboard'; +import { StxAvatar } from '@app/components/crypto-assets/stacks/components/stx-avatar'; +import { StampsIcon } from '@app/ui/components/avatar-icon//stamps-icon'; +import { OrdinalIcon } from '@app/ui/components/avatar-icon/ordinal-icon'; + +import { receiveTabStyle } from '../receive-dialog'; +import { ReceiveItem } from './receive-item'; + +interface ReceiveCollectiblesProps { + btcAddressTaproot: string; + btcAddressNativeSegwit: string; + stxAddress: string; + onClickQrOrdinal(): void; + onClickQrStacksNft(): void; + onClickQrStamp(): void; +} +export function ReceiveCollectibles({ + btcAddressTaproot, + btcAddressNativeSegwit, + stxAddress, + onClickQrOrdinal, + onClickQrStacksNft, + onClickQrStamp, +}: ReceiveCollectiblesProps) { + return ( + + } + dataTestId={HomePageSelectors.ReceiveBtcTaprootQrCodeBtn} + onCopyAddress={() => copyToClipboard(btcAddressTaproot)} + onClickQrCode={onClickQrOrdinal} + title="Ordinal inscription" + /> + } + onClickQrCode={onClickQrStamp} + onCopyAddress={() => copyToClipboard(btcAddressNativeSegwit)} + title="Bitcoin Stamp" + /> + } + onCopyAddress={() => copyToClipboard(stxAddress)} + onClickQrCode={onClickQrStacksNft} + title="Stacks NFT" + /> + + ); +} diff --git a/src/app/pages/receive/components/receive-items.tsx b/src/app/pages/receive/components/receive-items.tsx deleted file mode 100644 index 7a42aa5d28b..00000000000 --- a/src/app/pages/receive/components/receive-items.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Divider, Stack, styled } from 'leather-styles/jsx'; - -interface ReceiveItemListProps { - children: React.ReactNode; - title?: string; -} -export function ReceiveItemList({ children, title }: ReceiveItemListProps) { - return ( - <> - {title && ( - - {title} - - )} - - - {children} - - - ); -} diff --git a/src/app/pages/receive/components/receive-tokens.layout.tsx b/src/app/pages/receive/components/receive-tokens.layout.tsx index 3fc721c3bfc..86c7172b2d9 100644 --- a/src/app/pages/receive/components/receive-tokens.layout.tsx +++ b/src/app/pages/receive/components/receive-tokens.layout.tsx @@ -5,9 +5,11 @@ import { Box, Flex, styled } from 'leather-styles/jsx'; import { useLocationState } from '@app/common/hooks/use-location-state'; import { AddressDisplayer } from '@app/components/address-displayer/address-displayer'; -import { BaseDrawer } from '@app/components/drawer/base-drawer'; import { useBackgroundLocationRedirect } from '@app/routes/hooks/use-background-location-redirect'; import { Button } from '@app/ui/components/button/button'; +import { Dialog } from '@app/ui/components/containers/dialog/dialog'; +import { Footer } from '@app/ui/components/containers/footers/footer'; +import { Header } from '@app/ui/components/containers/headers/header'; import { QrCode } from './address-qr-code'; @@ -26,7 +28,24 @@ export function ReceiveTokensLayout(props: ReceiveTokensLayoutProps) { const backgroundLocation = useLocationState('backgroundLocation'); return ( - navigate(backgroundLocation ?? '..')}> + navigate(backgroundLocation ?? '..')} + /> + } + isShowing + onClose={() => navigate(backgroundLocation ?? '..')} + footer={ +
+ +
+ } + > {warning && warning} @@ -51,10 +70,7 @@ export function ReceiveTokensLayout(props: ReceiveTokensLayoutProps) { - -
+ ); } diff --git a/src/app/pages/receive/components/receive-tokens.tsx b/src/app/pages/receive/components/receive-tokens.tsx new file mode 100644 index 00000000000..d64acf158c5 --- /dev/null +++ b/src/app/pages/receive/components/receive-tokens.tsx @@ -0,0 +1,44 @@ +import { HomePageSelectors } from '@tests/selectors/home.selectors'; +import { css } from 'leather-styles/css'; +import { Stack } from 'leather-styles/jsx'; + +import { copyToClipboard } from '@app/common/utils/copy-to-clipboard'; +import { StxAvatar } from '@app/components/crypto-assets/stacks/components/stx-avatar'; +import { BtcIcon } from '@app/ui/components/avatar-icon/btc-icon'; + +import { receiveTabStyle } from '../receive-dialog'; +import { ReceiveItem } from './receive-item'; + +interface ReceiveTokensProps { + btcAddressNativeSegwit: string; + stxAddress: string; + onClickQrBtc(): void; + onClickQrStx(): void; +} +export function ReceiveTokens({ + btcAddressNativeSegwit, + stxAddress, + onClickQrBtc, + onClickQrStx, +}: ReceiveTokensProps) { + return ( + + } + dataTestId={HomePageSelectors.ReceiveBtcNativeSegwitQrCodeBtn} + onCopyAddress={() => copyToClipboard(btcAddressNativeSegwit)} + onClickQrCode={onClickQrBtc} + title="Bitcoin" + /> + } + dataTestId={HomePageSelectors.ReceiveStxQrCodeBtn} + onCopyAddress={() => copyToClipboard(stxAddress)} + onClickQrCode={onClickQrStx} + title="Stacks" + /> + + ); +} diff --git a/src/app/pages/receive/receive-btc.tsx b/src/app/pages/receive/receive-btc.tsx index a91b73be5e7..c4f90075f41 100644 --- a/src/app/pages/receive/receive-btc.tsx +++ b/src/app/pages/receive/receive-btc.tsx @@ -1,10 +1,9 @@ -import toast from 'react-hot-toast'; import { useLocation } from 'react-router-dom'; import get from 'lodash.get'; import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; -import { useClipboard } from '@app/common/hooks/use-copy-to-clipboard'; +import { copyToClipboard } from '@app/common/utils/copy-to-clipboard'; import { useBackgroundLocationRedirect } from '@app/routes/hooks/use-background-location-redirect'; import { useCurrentAccountIndex } from '@app/store/accounts/account'; import { useNativeSegwitAccountIndexAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks'; @@ -26,18 +25,13 @@ export function ReceiveBtcModal({ type = 'btc' }: ReceiveBtcModalType) { const activeAccountBtcAddress = useNativeSegwitAccountIndexAddressIndexZero(accountIndex); const btcAddress = get(state, 'btcAddress', activeAccountBtcAddress); - const { onCopy } = useClipboard(btcAddress); - - function copyToClipboard() { - void analytics.track('copy_btc_address_to_clipboard'); - toast.success('Copied to clipboard!'); - onCopy(); - } - return ( { + void analytics.track('copy_btc_address_to_clipboard'); + copyToClipboard(btcAddress); + }} title={type === 'btc-stamp' ? 'BITCOIN STAMP' : 'BTC'} /> ); diff --git a/src/app/pages/receive/receive-dialog.tsx b/src/app/pages/receive/receive-dialog.tsx new file mode 100644 index 00000000000..1ba14beaacc --- /dev/null +++ b/src/app/pages/receive/receive-dialog.tsx @@ -0,0 +1,126 @@ +import { useLocation, useNavigate } from 'react-router-dom'; + +import { HomePageSelectors } from '@tests/selectors/home.selectors'; +import { styled } from 'leather-styles/jsx'; +import get from 'lodash.get'; + +import { RouteUrls } from '@shared/route-urls'; + +import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; +import { useLocationState } from '@app/common/hooks/use-location-state'; +import { useBackgroundLocationRedirect } from '@app/routes/hooks/use-background-location-redirect'; +import { useZeroIndexTaprootAddress } from '@app/store/accounts/blockchain/bitcoin/bitcoin.hooks'; +import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks'; +import { useCurrentAccountStxAddressState } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; +import { Dialog } from '@app/ui/components/containers/dialog/dialog'; +import { Header } from '@app/ui/components/containers/headers/header'; +import { Tabs } from '@app/ui/components/tabs/tabs'; + +import { ReceiveCollectibles } from './components/receive-collectibles'; +import { ReceiveTokens } from './components/receive-tokens'; + +type ReceiveDialog = 'full' | 'collectible'; + +// TODO ask design ideally all tabs should match but choose-fee has a different variation +export const receiveTabStyle = { + mt: 'space.03', + paddingX: 'space.03', + pb: 'space.05', +}; + +interface ReceiveDialogProps { + type?: 'full' | 'collectible'; +} + +export function ReceiveDialog({ type = 'full' }: ReceiveDialogProps) { + useBackgroundLocationRedirect(); + const analytics = useAnalytics(); + const backgroundLocation = useLocationState('backgroundLocation'); + const navigate = useNavigate(); + const location = useLocation(); + const btcAddressNativeSegwit = useCurrentAccountNativeSegwitAddressIndexZero(); + const stxAddress = useCurrentAccountStxAddressState(); + const accountIndex = get(location.state, 'accountIndex', undefined); + const btcAddressTaproot = useZeroIndexTaprootAddress(accountIndex); + + const title = type === 'full' ? 'Choose asset to receive' : 'Receive collectible'; + + function Collectibles() { + return ( + { + void analytics.track('select_inscription_to_add_new_collectible'); + navigate(`${RouteUrls.Home}${RouteUrls.ReceiveCollectibleOrdinal}`, { + state: { + btcAddressTaproot, + backgroundLocation, + }, + }); + }} + onClickQrStamp={() => + navigate(`${RouteUrls.Home}${RouteUrls.ReceiveBtcStamp}`, { + state: { backgroundLocation }, + }) + } + onClickQrStacksNft={() => + navigate(`${RouteUrls.Home}${RouteUrls.ReceiveStx}`, { + state: { backgroundLocation }, + }) + } + /> + ); + } + + return ( + navigate(backgroundLocation ?? '..')} + title={{title}} + /> + } + onClose={() => navigate(backgroundLocation ?? '..')} + isShowing + > + {type === 'collectible' && } + {type === 'full' && ( + + + + Tokens + + + Collectibles + + + + + navigate(`${RouteUrls.Home}${RouteUrls.ReceiveBtc}`, { + state: { backgroundLocation }, + }) + } + onClickQrStx={() => + navigate(`${RouteUrls.Home}${RouteUrls.ReceiveStx}`, { + state: { backgroundLocation, btcAddressTaproot }, + }) + } + /> + + + + + + )} + + ); +} diff --git a/src/app/pages/receive/receive-modal.tsx b/src/app/pages/receive/receive-modal.tsx deleted file mode 100644 index b39ca8b0e75..00000000000 --- a/src/app/pages/receive/receive-modal.tsx +++ /dev/null @@ -1,151 +0,0 @@ -import toast from 'react-hot-toast'; -import { useLocation, useNavigate } from 'react-router-dom'; - -import { HomePageSelectors } from '@tests/selectors/home.selectors'; -import { Box, styled } from 'leather-styles/jsx'; -import get from 'lodash.get'; - -import { RouteUrls } from '@shared/route-urls'; - -import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; -import { useClipboard } from '@app/common/hooks/use-copy-to-clipboard'; -import { useLocationState } from '@app/common/hooks/use-location-state'; -import { BaseDrawer } from '@app/components/drawer/base-drawer'; -import { useBackgroundLocationRedirect } from '@app/routes/hooks/use-background-location-redirect'; -import { useZeroIndexTaprootAddress } from '@app/store/accounts/blockchain/bitcoin/bitcoin.hooks'; -import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks'; -import { useCurrentAccountStxAddressState } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; -import { BtcAvatarIcon } from '@app/ui/components/avatar/btc-avatar-icon'; -import { OrdinalAvatarIcon } from '@app/ui/components/avatar/ordinal-avatar-icon'; -import { StampsAvatarIcon } from '@app/ui/components/avatar/stamps-avatar-icon'; -import { StxAvatarIcon } from '@app/ui/components/avatar/stx-avatar-icon'; - -import { ReceiveItem } from './components/receive-item'; -import { ReceiveItemList } from './components/receive-items'; - -type ReceiveModal = 'full' | 'collectible'; - -interface ReceiveModalProps { - type?: 'full' | 'collectible'; -} - -export function ReceiveModal({ type = 'full' }: ReceiveModalProps) { - useBackgroundLocationRedirect(); - const analytics = useAnalytics(); - const backgroundLocation = useLocationState('backgroundLocation'); - const navigate = useNavigate(); - const location = useLocation(); - const btcAddressNativeSegwit = useCurrentAccountNativeSegwitAddressIndexZero(); - const stxAddress = useCurrentAccountStxAddressState(); - const accountIndex = get(location.state, 'accountIndex', undefined); - const btcAddressTaproot = useZeroIndexTaprootAddress(accountIndex); - - const { onCopy: onCopyBtc } = useClipboard(btcAddressNativeSegwit); - const { onCopy: onCopyStx } = useClipboard(stxAddress); - const { onCopy: onCopyOrdinal } = useClipboard(btcAddressTaproot); - - function copyToClipboard(copyHandler: () => void, tracker = 'copy_address_to_clipboard') { - void analytics.track(tracker); - toast.success('Copied to clipboard!'); - copyHandler(); - } - - const title = - type === 'full' ? ( - <> - Choose asset -
- to receive - - ) : ( - <> - Receive -
- collectible - - ); - - return ( - <> - navigate(backgroundLocation ?? '..')}> - - - {title} - - {type === 'full' && ( - - } - dataTestId={HomePageSelectors.ReceiveBtcNativeSegwitQrCodeBtn} - onCopyAddress={() => copyToClipboard(onCopyBtc)} - onClickQrCode={() => - navigate(`${RouteUrls.Home}${RouteUrls.ReceiveBtc}`, { - state: { backgroundLocation }, - }) - } - title="Bitcoin" - /> - } - dataTestId={HomePageSelectors.ReceiveStxQrCodeBtn} - onCopyAddress={() => copyToClipboard(onCopyStx)} - onClickQrCode={() => - navigate(`${RouteUrls.Home}${RouteUrls.ReceiveStx}`, { - state: { backgroundLocation, btcAddressTaproot }, - }) - } - title="Stacks" - /> - - )} - - } - dataTestId={HomePageSelectors.ReceiveBtcTaprootQrCodeBtn} - onCopyAddress={() => - copyToClipboard(onCopyOrdinal, 'select_stamp_to_add_new_collectible') - } - onClickQrCode={() => { - void analytics.track('select_inscription_to_add_new_collectible'); - navigate(`${RouteUrls.Home}${RouteUrls.ReceiveCollectibleOrdinal}`, { - state: { - btcAddressTaproot, - backgroundLocation, - }, - }); - }} - title="Ordinal inscription" - /> - } - onClickQrCode={() => - navigate(`${RouteUrls.Home}${RouteUrls.ReceiveBtcStamp}`, { - state: { backgroundLocation }, - }) - } - onCopyAddress={() => - copyToClipboard(onCopyBtc, 'select_stamp_to_add_new_collectible') - } - title="Bitcoin Stamp" - /> - } - onCopyAddress={() => copyToClipboard(onCopyStx, 'select_nft_to_add_new_collectible')} - onClickQrCode={() => - navigate(`${RouteUrls.Home}${RouteUrls.ReceiveStx}`, { - state: { backgroundLocation }, - }) - } - title="Stacks NFT" - /> - - - - - ); -} diff --git a/src/app/pages/receive/receive-ordinal.tsx b/src/app/pages/receive/receive-ordinal.tsx index a061131caca..b61036999b1 100644 --- a/src/app/pages/receive/receive-ordinal.tsx +++ b/src/app/pages/receive/receive-ordinal.tsx @@ -1,8 +1,7 @@ -import toast from 'react-hot-toast'; import { useLocation } from 'react-router-dom'; import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; -import { useClipboard } from '@app/common/hooks/use-copy-to-clipboard'; +import { copyToClipboard } from '@app/common/utils/copy-to-clipboard'; import { useBackgroundLocationRedirect } from '@app/routes/hooks/use-background-location-redirect'; import { ReceiveBtcModalWarning } from './components/receive-btc-warning'; @@ -12,18 +11,15 @@ export function ReceiveOrdinalModal() { useBackgroundLocationRedirect(); const analytics = useAnalytics(); const { state } = useLocation(); - const { onCopy } = useClipboard(state.btcAddressTaproot); - function copyToClipboard() { - void analytics.track('copy_address_to_add_new_inscription'); - toast.success('Copied to clipboard!'); - onCopy(); - } // #4028 FIXME - this doesn't open in new tab as it loses btcAddressTaproot amd crashes btcStamp and Stx are OK? return ( { + void analytics.track('copy_address_to_add_new_inscription'); + copyToClipboard(state.btcAddressTaproot); + }} title="ORD. INSCRIPTION" warning={} /> diff --git a/src/app/pages/receive/receive-stx.tsx b/src/app/pages/receive/receive-stx.tsx index c785a0e7de1..94c4a16d0c1 100644 --- a/src/app/pages/receive/receive-stx.tsx +++ b/src/app/pages/receive/receive-stx.tsx @@ -1,8 +1,6 @@ -import toast from 'react-hot-toast'; - import { useCurrentAccountDisplayName } from '@app/common/hooks/account/use-account-names'; import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; -import { useClipboard } from '@app/common/hooks/use-copy-to-clipboard'; +import { copyToClipboard } from '@app/common/utils/copy-to-clipboard'; import { useBackgroundLocationRedirect } from '@app/routes/hooks/use-background-location-redirect'; import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; @@ -12,22 +10,18 @@ export function ReceiveStxModal() { useBackgroundLocationRedirect(); const currentAccount = useCurrentStacksAccount(); const analytics = useAnalytics(); - const { onCopy } = useClipboard(currentAccount?.address ?? ''); const accountName = useCurrentAccountDisplayName(); - function copyToClipboard() { - void analytics.track('copy_stx_address_to_clipboard'); - toast.success('Copied to clipboard'); - onCopy(); - } - if (!currentAccount) return null; return ( { + void analytics.track('copy_stx_address_to_clipboard'); + copyToClipboard(currentAccount.address); + }} title="STX" /> ); diff --git a/src/app/pages/rpc-send-transfer/rpc-send-transfer-confirmation.tsx b/src/app/pages/rpc-send-transfer/rpc-send-transfer-confirmation.tsx index 03231b49b59..a144c96ce8a 100644 --- a/src/app/pages/rpc-send-transfer/rpc-send-transfer-confirmation.tsx +++ b/src/app/pages/rpc-send-transfer/rpc-send-transfer-confirmation.tsx @@ -61,7 +61,6 @@ export function RpcSendTransferConfirmation() { function formBtcTxSummaryState(txId: string) { return { - hasHeaderTitle: true, txLink: { blockchain: 'bitcoin', txid: txId || '', diff --git a/src/app/pages/rpc-send-transfer/rpc-send-transfer-container.tsx b/src/app/pages/rpc-send-transfer/rpc-send-transfer-container.tsx index a2340e4e06c..d7ff29bf6dc 100644 --- a/src/app/pages/rpc-send-transfer/rpc-send-transfer-container.tsx +++ b/src/app/pages/rpc-send-transfer/rpc-send-transfer-container.tsx @@ -4,9 +4,6 @@ import { Outlet, useOutletContext } from 'react-router-dom'; import { BtcFeeType } from '@shared/models/fees/bitcoin-fees.model'; import { closeWindow } from '@shared/utils'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; -import { PopupHeader } from '@app/features/current-account/popup-header'; - import { RpcSendTransferContainerLayout } from './components/rpc-send-transfer-container.layout'; import { useRpcSendTransfer } from './use-rpc-send-transfer'; @@ -23,8 +20,6 @@ export function RpcSendTransferContainer() { const [selectedFeeType, setSelectedFeeType] = useState(null); const { origin } = useRpcSendTransfer(); - useRouteHeader(); - if (origin === null) { closeWindow(); throw new Error('Origin is null'); diff --git a/src/app/pages/rpc-sign-bip322-message/rpc-sign-bip322-message.tsx b/src/app/pages/rpc-sign-bip322-message/rpc-sign-bip322-message.tsx index 192f19d16d1..2b5cffebb77 100644 --- a/src/app/pages/rpc-sign-bip322-message/rpc-sign-bip322-message.tsx +++ b/src/app/pages/rpc-sign-bip322-message/rpc-sign-bip322-message.tsx @@ -2,10 +2,8 @@ import { Outlet } from 'react-router-dom'; import { closeWindow } from '@shared/utils'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; import { Disclaimer } from '@app/components/disclaimer'; import { NoFeesWarningRow } from '@app/components/no-fees-warning-row'; -import { PopupHeader } from '@app/features/current-account/popup-header'; import { MessagePreviewBox } from '@app/features/message-signer/message-preview-box'; import { MessageSigningRequestLayout } from '@app/features/message-signer/message-signing-request.layout'; import { AccountGate } from '@app/routes/account-gate'; @@ -27,8 +25,6 @@ export function RpcSignBip322MessageRoute() { } function RpcSignBip322Message() { - useRouteHeader(); - const { origin, message, diff --git a/src/app/pages/rpc-sign-psbt/use-rpc-sign-psbt.tsx b/src/app/pages/rpc-sign-psbt/use-rpc-sign-psbt.tsx index a1a00da17ae..0ed40f404d2 100644 --- a/src/app/pages/rpc-sign-psbt/use-rpc-sign-psbt.tsx +++ b/src/app/pages/rpc-sign-psbt/use-rpc-sign-psbt.tsx @@ -61,7 +61,6 @@ export function useRpcSignPsbt() { const psbtTxSummaryState = { fee: formatMoneyPadded(fee), - hasHeaderTitle: true, sendingValue: formatMoney(transferTotalAsMoney), totalSpend: formatMoney(sumMoney([transferTotalAsMoney, fee])), txFiatValue: i18nFormatCurrency(calculateBitcoinFiatValue(transferTotalAsMoney)), diff --git a/src/app/pages/select-network/components/add-network-button.tsx b/src/app/pages/select-network/components/add-network-button.tsx deleted file mode 100644 index f26b43de8ed..00000000000 --- a/src/app/pages/select-network/components/add-network-button.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { SettingsSelectors } from '@tests/selectors/settings.selectors'; -import { Flex } from 'leather-styles/jsx'; - -import { Button } from '@app/ui/components/button/button'; - -interface AddNetworkButtonProps { - onAddNetwork(): void; -} -export function AddNetworkButton({ onAddNetwork }: AddNetworkButtonProps) { - return ( - - - - ); -} diff --git a/src/app/pages/select-network/components/network-list.layout.tsx b/src/app/pages/select-network/components/network-list.layout.tsx deleted file mode 100644 index 302dedf8429..00000000000 --- a/src/app/pages/select-network/components/network-list.layout.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { Flex, FlexProps } from 'leather-styles/jsx'; - -export function NetworkListLayout({ children, ...props }: FlexProps) { - return ( - - {children} - - ); -} diff --git a/src/app/pages/select-network/components/network-status-indicator.tsx b/src/app/pages/select-network/components/network-status-indicator.tsx deleted file mode 100644 index 5205ab80e70..00000000000 --- a/src/app/pages/select-network/components/network-status-indicator.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { CheckmarkIcon } from '@app/ui/icons/checkmark-icon'; -import { CloudOffIcon } from '@app/ui/icons/cloud-off-icon'; - -interface NetworkStatusIndicatorProps { - isActive: boolean; - isOnline: boolean; -} -export function NetworkStatusIndicator({ isActive, isOnline }: NetworkStatusIndicatorProps) { - return !isOnline ? : isActive ? : null; -} diff --git a/src/app/pages/select-network/select-network.tsx b/src/app/pages/select-network/select-network.tsx deleted file mode 100644 index 270036a87a9..00000000000 --- a/src/app/pages/select-network/select-network.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { useNavigate } from 'react-router-dom'; - -import { WalletDefaultNetworkConfigurationIds } from '@shared/constants'; -import { RouteUrls } from '@shared/route-urls'; - -import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; -import { useLocationState } from '@app/common/hooks/use-location-state'; -import { BaseDrawer } from '@app/components/drawer/base-drawer'; -import { NetworkListLayout } from '@app/pages/select-network/components/network-list.layout'; -import { NetworkListItem } from '@app/pages/select-network/network-list-item'; -import { useBackgroundLocationRedirect } from '@app/routes/hooks/use-background-location-redirect'; -import { useCurrentNetworkState, useNetworksActions } from '@app/store/networks/networks.hooks'; -import { useNetworks } from '@app/store/networks/networks.selectors'; - -import { AddNetworkButton } from './components/add-network-button'; - -const defaultNetworkIds = Object.values(WalletDefaultNetworkConfigurationIds) as string[]; - -export function SelectNetwork() { - useBackgroundLocationRedirect(); - const navigate = useNavigate(); - const networks = useNetworks(); - const analytics = useAnalytics(); - const networksActions = useNetworksActions(); - const currentNetwork = useCurrentNetworkState(); - const backgroundLocation = useLocationState('backgroundLocation'); - - function addNetwork() { - void analytics.track('add_network'); - navigate(RouteUrls.AddNetwork); - } - - function removeNetwork(id: string) { - void analytics.track('remove_network'); - networksActions.removeNetwork(id); - } - - function selectNetwork(id: string) { - void analytics.track('change_network', { id }); - networksActions.changeNetwork(id); - closeNetworkModal(); - } - - function closeNetworkModal() { - navigate(backgroundLocation ?? '..'); - } - - return ( - - - {Object.keys(networks).map(id => ( - selectNetwork(id)} - isCustom={!defaultNetworkIds.includes(id)} - onRemoveNetwork={id => { - if (id === currentNetwork.id) networksActions.changeNetwork('mainnet'); - removeNetwork(id); - }} - /> - ))} - - - - ); -} diff --git a/src/app/pages/send/choose-crypto-asset/choose-crypto-asset.tsx b/src/app/pages/send/choose-crypto-asset/choose-crypto-asset.tsx index 5e8c25d976b..f96c964a2f7 100644 --- a/src/app/pages/send/choose-crypto-asset/choose-crypto-asset.tsx +++ b/src/app/pages/send/choose-crypto-asset/choose-crypto-asset.tsx @@ -1,17 +1,17 @@ import toast from 'react-hot-toast'; import { useNavigate } from 'react-router-dom'; +import { styled } from 'leather-styles/jsx'; + import { AllTransferableCryptoAssetBalances } from '@shared/models/crypto-asset-balance.model'; import { RouteUrls } from '@shared/route-urls'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; import { useAllTransferableCryptoAssetBalances } from '@app/common/hooks/use-transferable-asset-balances.hooks'; import { useWalletType } from '@app/common/use-wallet-type'; -import { ChooseCryptoAssetLayout } from '@app/components/crypto-assets/choose-crypto-asset/choose-crypto-asset.layout'; import { CryptoAssetList } from '@app/components/crypto-assets/choose-crypto-asset/crypto-asset-list'; -import { ModalHeader } from '@app/components/modal-header'; import { useConfigBitcoinSendEnabled } from '@app/query/common/remote-config/remote-config.query'; import { useCheckLedgerBlockchainAvailable } from '@app/store/accounts/blockchain/utils'; +import { Card } from '@app/ui/layout/card/card'; export function ChooseCryptoAsset() { const allTransferableCryptoAssetBalances = useAllTransferableCryptoAssetBalances(); @@ -22,8 +22,6 @@ export function ChooseCryptoAsset() { const checkBlockchainAvailable = useCheckLedgerBlockchainAvailable(); - useRouteHeader(); - function navigateToSendForm(cryptoAssetBalance: AllTransferableCryptoAssetBalances) { const { asset } = cryptoAssetBalance; if (asset.symbol === 'BTC' && !isBitcoinSendEnabled) { @@ -44,7 +42,13 @@ export function ChooseCryptoAsset() { } return ( - + + choose asset
to send + + } + > navigateToSendForm(cryptoAssetBalance)} cryptoAssetBalances={allTransferableCryptoAssetBalances.filter(asset => @@ -54,6 +58,6 @@ export function ChooseCryptoAsset() { }) )} /> -
+ ); } diff --git a/src/app/pages/send/locked-bitcoin-summary/locked-bitcoin-summary.tsx b/src/app/pages/send/locked-bitcoin-summary/locked-bitcoin-summary.tsx index c8a5f034a2d..3dbdc831ad9 100644 --- a/src/app/pages/send/locked-bitcoin-summary/locked-bitcoin-summary.tsx +++ b/src/app/pages/send/locked-bitcoin-summary/locked-bitcoin-summary.tsx @@ -6,7 +6,6 @@ import { HStack, styled } from 'leather-styles/jsx'; import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; import { useBitcoinExplorerLink } from '@app/common/hooks/use-bitcoin-explorer-link'; import { useClipboard } from '@app/common/hooks/use-copy-to-clipboard'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; import { satToBtc } from '@app/common/money/unit-conversion'; import { InfoCard, @@ -14,7 +13,6 @@ import { InfoCardBtn, InfoCardFooter, } from '@app/components/info-card/info-card'; -import { ModalHeader } from '@app/components/modal-header'; import { CheckmarkIcon } from '@app/ui/icons/checkmark-icon'; import { CopyIcon } from '@app/ui/icons/copy-icon'; import { ExternalLinkIcon } from '@app/ui/icons/external-link-icon'; @@ -38,8 +36,6 @@ export function LockBitcoinSummary() { toast.success('ID copied!'); } - useRouteHeader(); - return ( - navigate(-1)}> + } + isShowing + onGoBack={() => navigate(-1)} + onClose={() => navigate(-1)} + > - + ); diff --git a/src/app/pages/send/ordinal-inscription/send-inscription-form.tsx b/src/app/pages/send/ordinal-inscription/send-inscription-form.tsx index 59d3e4f0afb..f16d0708e30 100644 --- a/src/app/pages/send/ordinal-inscription/send-inscription-form.tsx +++ b/src/app/pages/send/ordinal-inscription/send-inscription-form.tsx @@ -5,12 +5,13 @@ import { Box, Flex } from 'leather-styles/jsx'; import { RouteUrls } from '@shared/route-urls'; -import { BaseDrawer } from '@app/components/drawer/base-drawer'; import { ErrorLabel } from '@app/components/error-label'; import { InscriptionPreview } from '@app/components/inscription-preview-card/components/inscription-preview'; import { InscriptionPreviewCard } from '@app/components/inscription-preview-card/inscription-preview-card'; import { OrdinalAvatarIcon } from '@app/ui/components/avatar/ordinal-avatar-icon'; import { Button } from '@app/ui/components/button/button'; +import { Dialog } from '@app/ui/components/containers/dialog/dialog'; +import { Header } from '@app/ui/components/containers/headers/header'; import { RecipientAddressTypeField } from '../send-crypto-asset-form/components/recipient-address-type-field'; import { CollectibleAsset } from './components/collectible-asset'; @@ -37,7 +38,12 @@ export function SendInscriptionForm() { onSubmit={chooseTransactionFee} >
- navigate(RouteUrls.Home)}> + } + onGoBack={() => navigate(-1)} + isShowing + onClose={() => navigate(RouteUrls.Home)} + > Continue - +
); diff --git a/src/app/pages/send/ordinal-inscription/send-inscription-review.tsx b/src/app/pages/send/ordinal-inscription/send-inscription-review.tsx index c4a0d5ab348..66d9027a03e 100644 --- a/src/app/pages/send/ordinal-inscription/send-inscription-review.tsx +++ b/src/app/pages/send/ordinal-inscription/send-inscription-review.tsx @@ -8,13 +8,14 @@ import { RouteUrls } from '@shared/route-urls'; import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; import { FormAddressDisplayer } from '@app/components/address-displayer/form-address-displayer'; -import { BaseDrawer } from '@app/components/drawer/base-drawer'; import { InfoCard, InfoCardRow, InfoCardSeparator } from '@app/components/info-card/info-card'; import { InscriptionPreview } from '@app/components/inscription-preview-card/components/inscription-preview'; import { useCurrentNativeSegwitUtxos } from '@app/query/bitcoin/address/utxos-by-address.hooks'; import { useAppDispatch } from '@app/store'; import { inscriptionSent } from '@app/store/ordinals/ordinals.slice'; import { Button } from '@app/ui/components/button/button'; +import { Dialog } from '@app/ui/components/containers/dialog/dialog'; +import { Header } from '@app/ui/components/containers/headers/header'; import { InscriptionPreviewCard } from '../../../components/inscription-preview-card/inscription-preview-card'; import { useBitcoinBroadcastTransaction } from '../../../query/bitcoin/transaction/use-bitcoin-broadcast-transaction'; @@ -70,7 +71,12 @@ export function SendInscriptionReview() { } return ( - navigate(RouteUrls.Home)}> + } + isShowing + onGoBack={() => navigate(-1)} + onClose={() => navigate(RouteUrls.Home)} + > } @@ -91,6 +97,6 @@ export function SendInscriptionReview() { Confirm and send transaction
- + ); } diff --git a/src/app/pages/send/ordinal-inscription/sent-inscription-summary.tsx b/src/app/pages/send/ordinal-inscription/sent-inscription-summary.tsx index 7a1b051e65b..91b059c631f 100644 --- a/src/app/pages/send/ordinal-inscription/sent-inscription-summary.tsx +++ b/src/app/pages/send/ordinal-inscription/sent-inscription-summary.tsx @@ -12,7 +12,6 @@ import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; import { useBitcoinExplorerLink } from '@app/common/hooks/use-bitcoin-explorer-link'; import { useClipboard } from '@app/common/hooks/use-copy-to-clipboard'; import { FormAddressDisplayer } from '@app/components/address-displayer/form-address-displayer'; -import { BaseDrawer } from '@app/components/drawer/base-drawer'; import { InfoCard, InfoCardBtn, @@ -20,6 +19,8 @@ import { InfoCardSeparator, } from '@app/components/info-card/info-card'; import { InscriptionPreview } from '@app/components/inscription-preview-card/components/inscription-preview'; +import { Dialog } from '@app/ui/components/containers/dialog/dialog'; +import { Header } from '@app/ui/components/containers/headers/header'; import { CheckmarkIcon } from '@app/ui/icons/checkmark-icon'; import { CopyIcon } from '@app/ui/icons/copy-icon'; import { ExternalLinkIcon } from '@app/ui/icons/external-link-icon'; @@ -61,7 +62,11 @@ export function SendInscriptionSummary() { } return ( - navigate(RouteUrls.Home)}> + } + isShowing + onClose={() => navigate(RouteUrls.Home)} + > } @@ -84,6 +89,6 @@ export function SendInscriptionSummary() { } label="Copy ID" /> - + ); } diff --git a/src/app/pages/send/send-container.tsx b/src/app/pages/send/send-container.tsx deleted file mode 100644 index fca5abb1b6b..00000000000 --- a/src/app/pages/send/send-container.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { Outlet } from 'react-router-dom'; - -import { Flex } from 'leather-styles/jsx'; - -import { useRouteHeader } from '@app/common/hooks/use-route-header'; -import { whenPageMode } from '@app/common/utils'; -import { ModalHeader } from '@app/components/modal-header'; - -export function SendContainer() { - useRouteHeader(, true); - - return whenPageMode({ - full: ( - - - - ), - popup: ( - - - - ), - }); -} diff --git a/src/app/pages/send/send-crypto-asset-form/components/form-footer.tsx b/src/app/pages/send/send-crypto-asset-form/components/form-footer.tsx deleted file mode 100644 index 0333803e457..00000000000 --- a/src/app/pages/send/send-crypto-asset-form/components/form-footer.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { Box, Flex } from 'leather-styles/jsx'; - -import { Money } from '@shared/models/money.model'; - -import { whenPageMode } from '@app/common/utils'; -import { AvailableBalance } from '@app/components/available-balance'; -import { PreviewButton } from '@app/components/preview-button'; - -export function FormFooter(props: { balance: Money; balanceTooltipLabel?: string }) { - const { balance, balanceTooltipLabel } = props; - - return ( - - - - - - - ); -} diff --git a/src/app/pages/send/send-crypto-asset-form/components/recipient-accounts-drawer/account-list-item.tsx b/src/app/pages/send/send-crypto-asset-form/components/recipient-accounts-dialog/account-list-item.tsx similarity index 95% rename from src/app/pages/send/send-crypto-asset-form/components/recipient-accounts-drawer/account-list-item.tsx rename to src/app/pages/send/send-crypto-asset-form/components/recipient-accounts-dialog/account-list-item.tsx index d59114ed9d0..9b532794329 100644 --- a/src/app/pages/send/send-crypto-asset-form/components/recipient-accounts-drawer/account-list-item.tsx +++ b/src/app/pages/send/send-crypto-asset-form/components/recipient-accounts-dialog/account-list-item.tsx @@ -7,11 +7,11 @@ import { BitcoinSendFormValues, StacksSendFormValues } from '@shared/models/form import { useAccountDisplayName } from '@app/common/hooks/account/use-account-names'; import { AccountTotalBalance } from '@app/components/account-total-balance'; import { AcccountAddresses } from '@app/components/account/account-addresses'; -import { AccountAvatarItem } from '@app/components/account/account-avatar-item'; import { AccountListItemLayout } from '@app/components/account/account-list-item.layout'; import { AccountNameLayout } from '@app/components/account/account-name'; import { useNativeSegwitSigner } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks'; import { StacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.models'; +import { AccountAvatarItem } from '@app/ui/components/account/account-avatar/account-avatar-item'; interface AccountListItemProps { stacksAccount: StacksAccount; diff --git a/src/app/pages/send/send-crypto-asset-form/components/recipient-accounts-drawer/recipient-accounts-drawer.tsx b/src/app/pages/send/send-crypto-asset-form/components/recipient-accounts-dialog/recipient-accounts-dialog.tsx similarity index 60% rename from src/app/pages/send/send-crypto-asset-form/components/recipient-accounts-drawer/recipient-accounts-drawer.tsx rename to src/app/pages/send/send-crypto-asset-form/components/recipient-accounts-dialog/recipient-accounts-dialog.tsx index d14745b071e..dfb7ffb0138 100644 --- a/src/app/pages/send/send-crypto-asset-form/components/recipient-accounts-drawer/recipient-accounts-drawer.tsx +++ b/src/app/pages/send/send-crypto-asset-form/components/recipient-accounts-dialog/recipient-accounts-dialog.tsx @@ -2,15 +2,17 @@ import { memo, useCallback } from 'react'; import { useNavigate } from 'react-router-dom'; import { Virtuoso } from 'react-virtuoso'; +import { css } from 'leather-styles/css'; import { Box } from 'leather-styles/jsx'; -import { BaseDrawer } from '@app/components/drawer/base-drawer'; import { useFilteredBitcoinAccounts } from '@app/store/accounts/blockchain/bitcoin/bitcoin.ledger'; import { useStacksAccounts } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; +import { Dialog } from '@app/ui/components/containers/dialog/dialog'; +import { Header } from '@app/ui/components/containers/headers/header'; import { AccountListItem } from './account-list-item'; -export const RecipientAccountsDrawer = memo(() => { +export const RecipientAccountsDialog = memo(() => { const stacksAccounts = useStacksAccounts(); const navigate = useNavigate(); @@ -20,25 +22,26 @@ export const RecipientAccountsDrawer = memo(() => { const stacksAddressesNum = stacksAccounts.length; if (stacksAddressesNum === 0 && btcAddressesNum === 0) return null; - return ( - + } isShowing onClose={onGoBack}> + {/* // TODO check Kyrans margin needed */} ( - - - + )} - style={{ paddingTop: '24px', height: '70vh' }} totalCount={stacksAddressesNum || btcAddressesNum} /> - + ); }); diff --git a/src/app/pages/send/send-crypto-asset-form/components/recipient-accounts-drawer/select-account-button.tsx b/src/app/pages/send/send-crypto-asset-form/components/recipient-accounts-dialog/select-account-button.tsx similarity index 100% rename from src/app/pages/send/send-crypto-asset-form/components/recipient-accounts-drawer/select-account-button.tsx rename to src/app/pages/send/send-crypto-asset-form/components/recipient-accounts-dialog/select-account-button.tsx diff --git a/src/app/pages/send/send-crypto-asset-form/components/recipient-type-dropdown/recipient-type-dropdown.tsx b/src/app/pages/send/send-crypto-asset-form/components/recipient-type-dropdown/recipient-type-dropdown.tsx index ee9ecdc1f36..1ee2a369dbe 100644 --- a/src/app/pages/send/send-crypto-asset-form/components/recipient-type-dropdown/recipient-type-dropdown.tsx +++ b/src/app/pages/send/send-crypto-asset-form/components/recipient-type-dropdown/recipient-type-dropdown.tsx @@ -1,6 +1,6 @@ import { SendCryptoAssetSelectors } from '@tests/selectors/send.selectors'; -import { DropdownMenu } from '@app/ui/components/dowpdown-menu/dropdown-menu'; +import { DropdownMenu } from '@app/ui/components/dropdown-menu/dropdown-menu'; import { Flag } from '@app/ui/components/flag/flag'; import { ChevronDownIcon } from '@app/ui/icons'; diff --git a/src/app/pages/send/send-crypto-asset-form/components/send-crypto-asset-form.layout.tsx b/src/app/pages/send/send-crypto-asset-form/components/send-crypto-asset-form.layout.tsx index 38c13c25d95..dea87a8c4c4 100644 --- a/src/app/pages/send/send-crypto-asset-form/components/send-crypto-asset-form.layout.tsx +++ b/src/app/pages/send/send-crypto-asset-form/components/send-crypto-asset-form.layout.tsx @@ -1,23 +1,23 @@ import { SendCryptoAssetSelectors } from '@tests/selectors/send.selectors'; import { Flex } from 'leather-styles/jsx'; +import { CardContent } from '@app/ui/layout/card/card-content'; + interface SendCryptoAssetFormLayoutProps { children: React.ReactNode; } export function SendCryptoAssetFormLayout({ children }: SendCryptoAssetFormLayoutProps) { return ( - - {children} - + + + {children} + + ); } diff --git a/src/app/pages/send/send-crypto-asset-form/form/brc-20/brc-20-choose-fee.tsx b/src/app/pages/send/send-crypto-asset-form/form/brc-20/brc-20-choose-fee.tsx index 7ee86e62a8f..e29c6151cd0 100644 --- a/src/app/pages/send/send-crypto-asset-form/form/brc-20/brc-20-choose-fee.tsx +++ b/src/app/pages/send/send-crypto-asset-form/form/brc-20/brc-20-choose-fee.tsx @@ -10,7 +10,6 @@ import { BtcFeeType } from '@shared/models/fees/bitcoin-fees.model'; import { createMoney } from '@shared/models/money.model'; import { RouteUrls } from '@shared/route-urls'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; import { formFeeRowValue } from '@app/common/send/utils'; import { useGenerateUnsignedNativeSegwitSingleRecipientTx } from '@app/common/transactions/bitcoin/use-generate-bitcoin-tx'; import { @@ -19,7 +18,6 @@ import { } from '@app/components/bitcoin-fees-list/bitcoin-fees-list'; import { useBitcoinFeesList } from '@app/components/bitcoin-fees-list/use-bitcoin-fees-list'; import { LoadingSpinner } from '@app/components/loading-spinner'; -import { ModalHeader } from '@app/components/modal-header'; import { BitcoinChooseFee } from '@app/features/bitcoin-choose-fee/bitcoin-choose-fee'; import { useValidateBitcoinSpend } from '@app/features/bitcoin-choose-fee/hooks/use-validate-bitcoin-spend'; import { UtxoResponseItem } from '@app/query/bitcoin/bitcoin-client'; @@ -113,13 +111,6 @@ export function BrcChooseFee() { } } - function onGoBack() { - setSelectedFeeType(null); - navigate(-1); - } - - useRouteHeader(); - return isLoadingOrder ? ( ); - return ( - - + + - } - autoComplete="off" - /> - } name={ticker} symbol={ticker} /> - - -
  • 1. Create transfer inscription with amount to send
  • -
  • 2. Send transfer inscription to recipient of choice
  • -
    - { - openInNewTab( - 'https://leather.gitbook.io/guides/bitcoin/sending-brc-20-tokens' - ); - }} - textStyle="body.02" - > - Learn more - -
    -
    + + } + > + + + } + autoComplete="off" + /> + } name={tick} symbol={tick} /> + + +
  • 1. Create transfer inscription with amount to send
  • +
  • 2. Send transfer inscription to recipient of choice
  • +
    + { + openInNewTab( + 'https://leather.gitbook.io/guides/bitcoin/sending-brc-20-tokens' + ); + }} + textStyle="body.02" + > + Learn more + +
    +
    + - ); diff --git a/src/app/pages/send/send-crypto-asset-form/form/btc/btc-choose-fee.tsx b/src/app/pages/send/send-crypto-asset-form/form/btc/btc-choose-fee.tsx index 6303f932bb1..8feeb3f3cf2 100644 --- a/src/app/pages/send/send-crypto-asset-form/form/btc/btc-choose-fee.tsx +++ b/src/app/pages/send/send-crypto-asset-form/form/btc/btc-choose-fee.tsx @@ -4,10 +4,8 @@ import { BtcFeeType } from '@shared/models/fees/bitcoin-fees.model'; import { BitcoinSendFormValues } from '@shared/models/form.model'; import { useLocationStateWithCache } from '@app/common/hooks/use-location-state'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; import { BitcoinFeesList } from '@app/components/bitcoin-fees-list/bitcoin-fees-list'; import { useBitcoinFeesList } from '@app/components/bitcoin-fees-list/use-bitcoin-fees-list'; -import { ModalHeader } from '@app/components/modal-header'; import { BitcoinChooseFee } from '@app/features/bitcoin-choose-fee/bitcoin-choose-fee'; import { useValidateBitcoinSpend } from '@app/features/bitcoin-choose-fee/hooks/use-validate-bitcoin-spend'; import { UtxoResponseItem } from '@app/query/bitcoin/bitcoin-client'; @@ -26,7 +24,7 @@ export function useBtcChooseFeeState() { export function BtcChooseFee() { const { isSendingMax, txValues, utxos } = useBtcChooseFeeState(); const { selectedFeeType, setSelectedFeeType } = useSendBitcoinAssetContextState(); - const { amountAsMoney, onGoBack, previewTransaction } = useBtcChooseFee(); + const { amountAsMoney, previewTransaction } = useBtcChooseFee(); const { feesList, isLoading } = useBitcoinFeesList({ amount: amountAsMoney, @@ -41,8 +39,6 @@ export function BtcChooseFee() { isSendingMax ); - useRouteHeader(); - return ( <> ); - return ( - - - } - onSetIsSendingMax={onSetIsSendingMax} - isSendingMax={isSendingMax} - switchableAmount={ - - } - /> - } - name={btcBalance.asset.name} - symbol={symbol} - /> - - {currentNetwork.chain.bitcoin.bitcoinNetwork === 'testnet' && ( - - {'This is a Bitcoin testnet transaction. Funds have no value. '} - - Get testnet BTC here ↗ - - - )} - - - + + + + + } + > + + + } + onSetIsSendingMax={onSetIsSendingMax} + isSendingMax={isSendingMax} + switchableAmount={ + + } + /> + } + name={btcBalance.asset.name} + symbol={symbol} + /> + + {currentNetwork.chain.bitcoin.bitcoinNetwork === 'testnet' && ( + + {'This is a Bitcoin testnet transaction. '} + + Get testnet BTC here ↗ + + + )} + + + {/* This is for testing purposes only, to make sure the form is ready to be submitted. */} diff --git a/src/app/pages/send/send-crypto-asset-form/form/btc/use-btc-choose-fee.tsx b/src/app/pages/send/send-crypto-asset-form/form/btc/use-btc-choose-fee.tsx index 55f5dcb07d7..b47a92ffbd3 100644 --- a/src/app/pages/send/send-crypto-asset-form/form/btc/use-btc-choose-fee.tsx +++ b/src/app/pages/send/send-crypto-asset-form/form/btc/use-btc-choose-fee.tsx @@ -1,7 +1,4 @@ -import { useNavigate } from 'react-router-dom'; - import { logger } from '@shared/logger'; -import { BtcFeeType } from '@shared/models/fees/bitcoin-fees.model'; import { createMoney } from '@shared/models/money.model'; import { btcToSat } from '@app/common/money/unit-conversion'; @@ -10,27 +7,20 @@ import { useGenerateUnsignedNativeSegwitSingleRecipientTx } from '@app/common/tr import { OnChooseFeeArgs } from '@app/components/bitcoin-fees-list/bitcoin-fees-list'; import { useSignBitcoinTx } from '@app/store/accounts/blockchain/bitcoin/bitcoin.hooks'; -import { useSendBitcoinAssetContextState } from '../../family/bitcoin/components/send-bitcoin-asset-container'; import { useCalculateMaxBitcoinSpend } from '../../family/bitcoin/hooks/use-calculate-max-spend'; import { useSendFormNavigate } from '../../hooks/use-send-form-navigate'; import { useBtcChooseFeeState } from './btc-choose-fee'; export function useBtcChooseFee() { const { isSendingMax, txValues, utxos } = useBtcChooseFeeState(); - const navigate = useNavigate(); const sendFormNavigate = useSendFormNavigate(); const generateTx = useGenerateUnsignedNativeSegwitSingleRecipientTx(); - const { setSelectedFeeType } = useSendBitcoinAssetContextState(); const calcMaxSpend = useCalculateMaxBitcoinSpend(); const signTx = useSignBitcoinTx(); const amountAsMoney = createMoney(btcToSat(txValues.amount).toNumber(), 'BTC'); return { amountAsMoney, - onGoBack() { - setSelectedFeeType(BtcFeeType.Standard); - navigate(-1); - }, async previewTransaction({ feeRate, feeValue, time, isCustomFee }: OnChooseFeeArgs) { const resp = await generateTx( diff --git a/src/app/pages/send/send-crypto-asset-form/form/stacks/stacks-common-send-form.tsx b/src/app/pages/send/send-crypto-asset-form/form/stacks/stacks-common-send-form.tsx index 88ed4fa7bee..8fd0b2c8bbb 100644 --- a/src/app/pages/send/send-crypto-asset-form/form/stacks/stacks-common-send-form.tsx +++ b/src/app/pages/send/send-crypto-asset-form/form/stacks/stacks-common-send-form.tsx @@ -1,22 +1,28 @@ import { Outlet, useNavigate } from 'react-router-dom'; +import { SendCryptoAssetSelectors } from '@tests/selectors/send.selectors'; +import BigNumber from 'bignumber.js'; import { Form, Formik, FormikHelpers } from 'formik'; import { Box } from 'leather-styles/jsx'; import { ObjectSchema } from 'yup'; -import { HIGH_FEE_WARNING_LEARN_MORE_URL_STX } from '@shared/constants'; +import { HIGH_FEE_AMOUNT_STX, HIGH_FEE_WARNING_LEARN_MORE_URL_STX } from '@shared/constants'; import { Fees } from '@shared/models/fees/fees.model'; import { StacksSendFormValues } from '@shared/models/form.model'; import { Money } from '@shared/models/money.model'; import { RouteUrls } from '@shared/route-urls'; +import { formatMoney } from '@app/common/money/format-money'; import { FeesRow } from '@app/components/fees-row/fees-row'; import { NonceSetter } from '@app/components/nonce-setter'; -import { HighFeeDrawer } from '@app/features/high-fee-drawer/high-fee-drawer'; +import { HighFeeDialog } from '@app/features/dialogs/high-fee-dialog/high-fee-dialog'; import { useUpdatePersistedSendFormValues } from '@app/features/popup-send-form-restoration/use-update-persisted-send-form-values'; +import { Button } from '@app/ui/components/button/button'; +import { AvailableBalance } from '@app/ui/components/containers/footers/available-balance'; +import { Footer } from '@app/ui/components/containers/footers/footer'; import { Link } from '@app/ui/components/link/link'; +import { Card } from '@app/ui/layout/card/card'; -import { FormFooter } from '../../components/form-footer'; import { MemoField } from '../../components/memo-field'; import { SendCryptoAssetFormLayout } from '../../components/send-crypto-asset-form.layout'; import { StacksRecipientField } from '../../family/stacks/components/stacks-recipient-field'; @@ -33,6 +39,7 @@ interface StacksCommonSendFormProps { selectedAssetField: React.JSX.Element; availableTokenBalance: Money; fees?: Fees; + fee?: number | string | BigNumber; } export function StacksCommonSendForm({ @@ -42,11 +49,11 @@ export function StacksCommonSendForm({ amountField, selectedAssetField, fees, + fee, availableTokenBalance, }: StacksCommonSendFormProps) { const navigate = useNavigate(); const { onFormStateChange } = useUpdatePersistedSendFormValues(); - return (
    - - {amountField} - {selectedAssetField} - - - - - - navigate(RouteUrls.EditNonce)} - > - Edit nonce - - - - + + + + + } + > + + {amountField} + {selectedAssetField} + + + + + + navigate(RouteUrls.EditNonce)} + > + Edit nonce + + + + + diff --git a/src/app/pages/send/send-crypto-asset-form/form/stacks/stacks-send-form-confirmation.tsx b/src/app/pages/send/send-crypto-asset-form/form/stacks/stacks-send-form-confirmation.tsx index 8bb9e4fb5b7..d91454baed6 100644 --- a/src/app/pages/send/send-crypto-asset-form/form/stacks/stacks-send-form-confirmation.tsx +++ b/src/app/pages/send/send-crypto-asset-form/form/stacks/stacks-send-form-confirmation.tsx @@ -1,4 +1,4 @@ -import { Outlet, useNavigate, useParams } from 'react-router-dom'; +import { Outlet, useParams } from 'react-router-dom'; import { deserializeTransaction } from '@stacks/transactions'; import { Box, Stack } from 'leather-styles/jsx'; @@ -6,8 +6,6 @@ import { Box, Stack } from 'leather-styles/jsx'; import { CryptoCurrencies } from '@shared/models/currencies.model'; import { useLocationStateWithCache } from '@app/common/hooks/use-location-state'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; -import { ModalHeader } from '@app/components/modal-header'; import { useStacksBroadcastTransaction } from '@app/features/stacks-transaction-request/hooks/use-stacks-broadcast-transaction'; import { useStacksTransactionSummary } from '@app/features/stacks-transaction-request/hooks/use-stacks-transaction-summary'; import { BasicTooltip } from '@app/ui/components/tooltip/basic-tooltip'; @@ -26,7 +24,6 @@ function useStacksSendFormConfirmationState() { export function StacksSendFormConfirmation() { const { tx, decimals, showFeeChangeWarning } = useStacksSendFormConfirmationState(); const { symbol = 'STX' } = useParams(); - const navigate = useNavigate(); const { stacksBroadcastTransaction, isBroadcasting } = useStacksBroadcastTransaction( symbol.toUpperCase() as CryptoCurrencies, @@ -51,15 +48,6 @@ export function StacksSendFormConfirmation() { memoDisplayText, } = formReviewTxSummary(stacksDeserializedTransaction, symbol, decimals); - useRouteHeader( - navigate('../', { relative: 'path', replace: true })} - title="Review" - /> - ); - const feeWarningTooltip = showFeeChangeWarning ? ( ) { // Validate and check high fee warning first const formErrors = formikHelpers.validateForm(); - if ( - !isShowingHighFeeConfirmation && - isEmpty(formErrors) && - new BigNumber(values.fee).isGreaterThan(HIGH_FEE_AMOUNT_STX) - ) { - setIsShowingHighFeeConfirmation(true); + // TODO - check as this seems to only validate HighFees + // See PR https://github.com/leather-wallet/extension/pull/3486/ + if (isEmpty(formErrors) && new BigNumber(values.fee).isGreaterThan(HIGH_FEE_AMOUNT_STX)) { return false; } return true; diff --git a/src/app/pages/send/send-crypto-asset-form/form/stx/stx-send-form.tsx b/src/app/pages/send/send-crypto-asset-form/form/stx/stx-send-form.tsx index 870350795c6..0e95742f203 100644 --- a/src/app/pages/send/send-crypto-asset-form/form/stx/stx-send-form.tsx +++ b/src/app/pages/send/send-crypto-asset-form/form/stx/stx-send-form.tsx @@ -22,6 +22,7 @@ export function StxSendForm() { sendMaxBalance, stxFees: fees, validationSchema, + fee, } = useStxSendForm(); const amountField = ( @@ -47,6 +48,9 @@ export function StxSendForm() { amountField={amountField} selectedAssetField={selectedAssetField} fees={fees} + // FIXME 4370 - need to fix this as fee is actually NumberSchema; in FeeValidatorFactoryArgs + // this needs to be the STX fee so it can be validated against HIGH_FEE_AMOUNT_STX + fee={fee as unknown as string} availableTokenBalance={availableStxBalance} /> ); diff --git a/src/app/pages/send/send-crypto-asset-form/form/stx/use-stx-send-form.tsx b/src/app/pages/send/send-crypto-asset-form/form/stx/use-stx-send-form.tsx index 61aee92f800..b726551845c 100644 --- a/src/app/pages/send/send-crypto-asset-form/form/stx/use-stx-send-form.tsx +++ b/src/app/pages/send/send-crypto-asset-form/form/stx/use-stx-send-form.tsx @@ -50,16 +50,20 @@ export function useStxSendForm() { availableTokenBalance: availableStxBalance, }); + // FIXME - I don't this this is the fee, should be value.fee or something from the form + const fee = stxFeeValidator(availableStxBalance); + return { availableStxBalance, initialValues, onFormStateChange, sendMaxBalance, stxFees, + fee, validationSchema: yup.object({ amount: stxAmountValidator().concat(stxAvailableBalanceValidator(availableStxBalance)), - fee: stxFeeValidator(availableStxBalance), + fee, recipient, memo, nonce, diff --git a/src/app/pages/send/send-crypto-asset-form/hooks/use-send-form-navigate.ts b/src/app/pages/send/send-crypto-asset-form/hooks/use-send-form-navigate.ts index df0de5edb5a..4243f5411d4 100644 --- a/src/app/pages/send/send-crypto-asset-form/hooks/use-send-form-navigate.ts +++ b/src/app/pages/send/send-crypto-asset-form/hooks/use-send-form-navigate.ts @@ -14,7 +14,6 @@ interface ConfirmationRouteState { decimals?: number; token?: string; tx: string; - hasHeaderTitle?: boolean; } interface ConfirmationRouteStacksSip10Args { @@ -49,7 +48,6 @@ export function useSendFormNavigate() { isSendingMax, utxos, values, - hasHeaderTitle: true, }, }); }, @@ -67,7 +65,6 @@ export function useSendFormNavigate() { fee, feeRowValue, time, - hasHeaderTitle: true, } as ConfirmationRouteState, }); }, @@ -76,7 +73,6 @@ export function useSendFormNavigate() { replace: true, state: { tx: bytesToHex(tx.serialize()), - hasHeaderTitle: true, showFeeChangeWarning, } as ConfirmationRouteState, }); diff --git a/src/app/pages/send/send-crypto-asset-form/send-crypto-asset-form.routes.tsx b/src/app/pages/send/send-crypto-asset-form/send-crypto-asset-form.routes.tsx index 8ad33c31f81..01fec10cac8 100644 --- a/src/app/pages/send/send-crypto-asset-form/send-crypto-asset-form.routes.tsx +++ b/src/app/pages/send/send-crypto-asset-form/send-crypto-asset-form.routes.tsx @@ -1,23 +1,23 @@ import { Suspense } from 'react'; -import { Route } from 'react-router-dom'; +import { Outlet, Route } from 'react-router-dom'; import { RouteUrls } from '@shared/route-urls'; -import { BroadcastErrorDrawer } from '@app/components/broadcast-error-drawer/broadcast-error-drawer'; +import { BroadcastErrorDialog } from '@app/components/broadcast-error-dialog/broadcast-error-dialog'; import { SendBtcDisabled } from '@app/components/crypto-assets/choose-crypto-asset/send-btc-disabled'; import { FullPageWithHeaderLoadingSpinner } from '@app/components/loading-spinner'; -import { EditNonceDrawer } from '@app/features/edit-nonce-drawer/edit-nonce-drawer'; +import { EditNonceDialog } from '@app/features/dialogs/edit-nonce-dialog/edit-nonce-dialog'; import { ledgerBitcoinTxSigningRoutes } from '@app/features/ledger/flows/bitcoin-tx-signing/ledger-bitcoin-sign-tx-container'; import { ledgerStacksTxSigningRoutes } from '@app/features/ledger/flows/stacks-tx-signing/ledger-sign-stacks-tx-container'; import { AccountGate } from '@app/routes/account-gate'; +import { Page } from '@app/ui/layout/page/page.layout'; import { BroadcastError } from '../broadcast-error/broadcast-error'; import { ChooseCryptoAsset } from '../choose-crypto-asset/choose-crypto-asset'; -import { SendContainer } from '../send-container'; import { Brc20SentSummary } from '../sent-summary/brc20-sent-summary'; import { BtcSentSummary } from '../sent-summary/btc-sent-summary'; import { StxSentSummary } from '../sent-summary/stx-sent-summary'; -import { RecipientAccountsDrawer } from './components/recipient-accounts-drawer/recipient-accounts-drawer'; +import { RecipientAccountsDialog } from './components/recipient-accounts-dialog/recipient-accounts-dialog'; import { SendBitcoinAssetContainer } from './family/bitcoin/components/send-bitcoin-asset-container'; import { Brc20SendForm } from './form/brc-20/brc20-send-form'; import { Brc20SendFormConfirmation } from './form/brc-20/brc20-send-form-confirmation'; @@ -29,20 +29,26 @@ import { Sip10TokenSendForm } from './form/stacks-sip10/sip10-token-send-form'; import { StacksSendFormConfirmation } from './form/stacks/stacks-send-form-confirmation'; import { StxSendForm } from './form/stx/stx-send-form'; -const recipientAccountsDrawerRoute = ( +const recipientAccountsDialogRoute = ( } + element={} /> ); -const editNonceDrawerRoute = } />; -const broadcastErrorDrawerRoute = ( - } /> +const editNonceDialogRoute = } />; +const broadcastErrorDialogRoute = ( + } /> ); export const sendCryptoAssetFormRoutes = ( - }> + + + + } + > } /> - }> } > {ledgerBitcoinTxSigningRoutes} - {recipientAccountsDrawerRoute} + {recipientAccountsDialogRoute} - } /> - } /> + } /> + } /> - } /> + } /> }> {ledgerBitcoinTxSigningRoutes} @@ -78,11 +83,10 @@ export const sendCryptoAssetFormRoutes = ( } /> } /> - }> - {broadcastErrorDrawerRoute} - {editNonceDrawerRoute} - {recipientAccountsDrawerRoute} + {broadcastErrorDialogRoute} + {editNonceDialogRoute} + {recipientAccountsDialogRoute} {ledgerStacksTxSigningRoutes} - }> - {broadcastErrorDrawerRoute} - {editNonceDrawerRoute} - {recipientAccountsDrawerRoute} + {broadcastErrorDialogRoute} + {editNonceDialogRoute} + {recipientAccountsDialogRoute} }> {ledgerStacksTxSigningRoutes} - } /> ); diff --git a/src/app/pages/send/sent-summary/brc20-sent-summary.tsx b/src/app/pages/send/sent-summary/brc20-sent-summary.tsx index 6b2748160d4..d610a1318bb 100644 --- a/src/app/pages/send/sent-summary/brc20-sent-summary.tsx +++ b/src/app/pages/send/sent-summary/brc20-sent-summary.tsx @@ -5,7 +5,6 @@ import get from 'lodash.get'; import { createMoney } from '@shared/models/money.model'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; import { HandleOpenStacksTxLinkArgs } from '@app/common/hooks/use-stacks-explorer-link'; import { formatMoney } from '@app/common/money/format-money'; import { openInNewTab } from '@app/common/utils/open-in-new-tab'; @@ -17,7 +16,6 @@ import { InfoCardRow, InfoCardSeparator, } from '@app/components/info-card/info-card'; -import { ModalHeader } from '@app/components/modal-header'; import { Callout } from '@app/ui/components/callout/callout'; import { Link } from '@app/ui/components/link/link'; import { ExternalLinkIcon } from '@app/ui/icons/external-link-icon'; @@ -47,8 +45,6 @@ export function Brc20SentSummary() { navigate('/'); } - useRouteHeader(); - return ( diff --git a/src/app/pages/send/sent-summary/btc-sent-summary.tsx b/src/app/pages/send/sent-summary/btc-sent-summary.tsx index 2a641c41ee9..565ab847988 100644 --- a/src/app/pages/send/sent-summary/btc-sent-summary.tsx +++ b/src/app/pages/send/sent-summary/btc-sent-summary.tsx @@ -6,7 +6,6 @@ import { HStack, Stack } from 'leather-styles/jsx'; import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; import { useBitcoinExplorerLink } from '@app/common/hooks/use-bitcoin-explorer-link'; import { useClipboard } from '@app/common/hooks/use-copy-to-clipboard'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; import { FormAddressDisplayer } from '@app/components/address-displayer/form-address-displayer'; import { InfoCard, @@ -16,7 +15,6 @@ import { InfoCardRow, InfoCardSeparator, } from '@app/components/info-card/info-card'; -import { ModalHeader } from '@app/components/modal-header'; import { CopyIcon } from '@app/ui/icons/copy-icon'; import { ExternalLinkIcon } from '@app/ui/icons/external-link-icon'; @@ -53,8 +51,6 @@ export function BtcSentSummary() { toast.success('ID copied!'); } - useRouteHeader(); - return ( diff --git a/src/app/pages/send/sent-summary/stx-sent-summary.tsx b/src/app/pages/send/sent-summary/stx-sent-summary.tsx index a8f1d6e4fda..e9bac0eb7e4 100644 --- a/src/app/pages/send/sent-summary/stx-sent-summary.tsx +++ b/src/app/pages/send/sent-summary/stx-sent-summary.tsx @@ -5,7 +5,6 @@ import { HStack, Stack } from 'leather-styles/jsx'; import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; import { useClipboard } from '@app/common/hooks/use-copy-to-clipboard'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; import { useStacksExplorerLink } from '@app/common/hooks/use-stacks-explorer-link'; import { whenPageMode } from '@app/common/utils'; import { FormAddressDisplayer } from '@app/components/address-displayer/form-address-displayer'; @@ -17,7 +16,6 @@ import { InfoCardRow, InfoCardSeparator, } from '@app/components/info-card/info-card'; -import { ModalHeader } from '@app/components/modal-header'; import { CopyIcon } from '@app/ui/icons/copy-icon'; import { ExternalLinkIcon } from '@app/ui/icons/external-link-icon'; @@ -54,8 +52,6 @@ export function StxSentSummary() { toast.success('ID copied!'); } - useRouteHeader(); - return ( - -
    - - When you sign out, - {whenWallet({ - software: ` you'll need your Secret Key to sign back in. Only sign out if you've backed up your Secret Key.`, - ledger: ` you'll need to reconnect your Ledger to sign back into your wallet.`, - })} - - - {whenWallet({ - software: ( - } spacing="space.02"> - If you haven't backed up your Secret Key, you will lose all your funds. - - ), - ledger: <>, - })} - - - - - - - I've backed up my Secret Key - - - - - - - - I understand my password will no longer work for accessing my wallet upon signing out - - - - - - -
    -
    - - ); -} diff --git a/src/app/pages/sign-out-confirm/sign-out-confirm.tsx b/src/app/pages/sign-out-confirm/sign-out-confirm.tsx deleted file mode 100644 index b335ec8ed8a..00000000000 --- a/src/app/pages/sign-out-confirm/sign-out-confirm.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { useNavigate } from 'react-router-dom'; - -import { RouteUrls } from '@shared/route-urls'; - -import { useKeyActions } from '@app/common/hooks/use-key-actions'; -import { useLocationState } from '@app/common/hooks/use-location-state'; -import { useBackgroundLocationRedirect } from '@app/routes/hooks/use-background-location-redirect'; - -import { SignOutConfirmLayout } from './sign-out-confirm.layout'; - -export function SignOutConfirmDrawer() { - useBackgroundLocationRedirect(); - const { signOut } = useKeyActions(); - const navigate = useNavigate(); - const backgroundLocation = useLocationState('backgroundLocation'); - - return ( - { - void signOut().finally(() => { - navigate(RouteUrls.Onboarding); - }); - }} - onUserSafelyReturnToHomepage={() => navigate(backgroundLocation ?? '..')} - /> - ); -} diff --git a/src/app/pages/swap/alex-swap-container.tsx b/src/app/pages/swap/alex-swap-container.tsx index ec4258915e8..9c63b3d469e 100644 --- a/src/app/pages/swap/alex-swap-container.tsx +++ b/src/app/pages/swap/alex-swap-container.tsx @@ -22,8 +22,8 @@ import { defaultFeesMinValuesAsMoney } from '@app/query/stacks/fees/fees.utils'; import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; import { useGenerateStacksContractCallUnsignedTx } from '@app/store/transactions/contract-call.hooks'; import { useSignStacksTransaction } from '@app/store/transactions/transaction.hooks'; +import { Page } from '@app/ui/layout/page/page.layout'; -import { SwapContainerLayout } from './components/swap-container.layout'; import { SwapForm } from './components/swap-form'; import { generateSwapRoutes } from './generate-swap-routes'; import { useAlexBroadcastSwap } from './hooks/use-alex-broadcast-swap'; @@ -201,12 +201,12 @@ function AlexSwapContainer() { return ( - + - + ); } diff --git a/src/app/pages/swap/components/swap-container.layout.tsx b/src/app/pages/swap/components/swap-container.layout.tsx deleted file mode 100644 index f91471633a0..00000000000 --- a/src/app/pages/swap/components/swap-container.layout.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Flex } from 'leather-styles/jsx'; - -import { HasChildren } from '@app/common/has-children'; -import { whenPageMode } from '@app/common/utils'; - -export function SwapContainerLayout({ children }: HasChildren) { - return whenPageMode({ - full: ( - - {children} - - ), - popup: ( - - {children} - - ), - }); -} diff --git a/src/app/pages/swap/swap-choose-asset/components/swap-asset-list.layout.tsx b/src/app/pages/swap/swap-choose-asset/components/swap-asset-list.layout.tsx deleted file mode 100644 index eb40bfdcbf4..00000000000 --- a/src/app/pages/swap/swap-choose-asset/components/swap-asset-list.layout.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { Stack, StackProps } from 'leather-styles/jsx'; - -export function SwapAssetListLayout({ children }: StackProps) { - return ( - - {children} - - ); -} diff --git a/src/app/pages/swap/swap-choose-asset/components/swap-asset-list.tsx b/src/app/pages/swap/swap-choose-asset/components/swap-asset-list.tsx index 32c2028fd89..66e74b55051 100644 --- a/src/app/pages/swap/swap-choose-asset/components/swap-asset-list.tsx +++ b/src/app/pages/swap/swap-choose-asset/components/swap-asset-list.tsx @@ -2,6 +2,7 @@ import { useNavigate } from 'react-router-dom'; import BigNumber from 'bignumber.js'; import { useFormikContext } from 'formik'; +import { Stack } from 'leather-styles/jsx'; import { createMoney } from '@shared/models/money.model'; import { isUndefined } from '@shared/utils'; @@ -13,7 +14,6 @@ import { useSwapContext } from '@app/pages/swap/swap.context'; import { SwapAsset, SwapFormValues } from '../../hooks/use-swap-form'; import { useSwapChooseAssetState } from '../swap-choose-asset'; import { SwapAssetItem } from './swap-asset-item'; -import { SwapAssetListLayout } from './swap-asset-list.layout'; interface SwapAssetList { assets: SwapAsset[]; @@ -46,6 +46,7 @@ export function SwapAssetList({ assets }: SwapAssetList) { await setFieldValue('swapAssetTo', asset); setFieldError('swapAssetTo', undefined); } + navigate(-1); if (from && to && values.swapAmountFrom) { const toAmount = await fetchToAmount(from, to, values.swapAmountFrom); @@ -64,7 +65,7 @@ export function SwapAssetList({ assets }: SwapAssetList) { } return ( - + {selectableAssets.map(asset => ( onChooseAsset(asset)} /> ))} - +
    ); } diff --git a/src/app/pages/swap/swap-choose-asset/swap-choose-asset.tsx b/src/app/pages/swap/swap-choose-asset/swap-choose-asset.tsx index d095c762849..94fbb94eb1c 100644 --- a/src/app/pages/swap/swap-choose-asset/swap-choose-asset.tsx +++ b/src/app/pages/swap/swap-choose-asset/swap-choose-asset.tsx @@ -4,7 +4,9 @@ import { SwapSelectors } from '@tests/selectors/swap.selectors'; import { Box, styled } from 'leather-styles/jsx'; import get from 'lodash.get'; -import { BaseDrawer } from '@app/components/drawer/base-drawer'; +import { RouteUrls } from '@shared/route-urls'; + +import { Dialog } from '@app/ui/components/containers/dialog/dialog'; import { useSwapContext } from '../swap.context'; import { SwapAssetList } from './components/swap-asset-list'; @@ -22,28 +24,15 @@ export function SwapChooseAsset() { const isFromList = swapListType === 'from'; - const title = isFromList ? ( - <> - Choose asset -
    - to swap - - ) : ( - <> - Choose asset -
    - to receive - - ); + const title = isFromList ? 'Choose asset to swap' : 'Choose asset to receive'; return ( - navigate(-1)}> - - - {title} - + navigate(RouteUrls.Swap)}> + {/* try replace below height with dialog and get rid of box */} + + {title} - + ); } diff --git a/src/app/pages/swap/swap-review/swap-review.tsx b/src/app/pages/swap/swap-review/swap-review.tsx index accef3a66a9..71ee8a184d2 100644 --- a/src/app/pages/swap/swap-review/swap-review.tsx +++ b/src/app/pages/swap/swap-review/swap-review.tsx @@ -3,8 +3,6 @@ import { Outlet } from 'react-router-dom'; import { SwapSelectors } from '@tests/selectors/swap.selectors'; import { LoadingKeys, useLoading } from '@app/common/hooks/use-loading'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; -import { ModalHeader } from '@app/components/modal-header'; import { Button } from '@app/ui/components/button/button'; import { SwapAssetsPair } from '../components/swap-assets-pair/swap-assets-pair'; @@ -18,8 +16,6 @@ export function SwapReview() { const { onSubmitSwap } = useSwapContext(); const { isLoading } = useLoading(LoadingKeys.SUBMIT_SWAP_TRANSACTION); - useRouteHeader(, true); - return ( <> diff --git a/src/app/pages/swap/swap.tsx b/src/app/pages/swap/swap.tsx index 64b8cb5fce4..640dac5d980 100644 --- a/src/app/pages/swap/swap.tsx +++ b/src/app/pages/swap/swap.tsx @@ -6,9 +6,7 @@ import { useFormikContext } from 'formik'; import { isUndefined } from '@shared/utils'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; import { LoadingSpinner } from '@app/components/loading-spinner'; -import { ModalHeader } from '@app/components/modal-header'; import { Button } from '@app/ui/components/button/button'; import { SwapContentLayout } from './components/swap-content.layout'; @@ -21,8 +19,6 @@ export function Swap() { const { isFetchingExchangeRate, swappableAssetsFrom } = useSwapContext(); const { dirty, isValid, setFieldValue, values } = useFormikContext(); - useRouteHeader(, true); - useAsync(async () => { if (isUndefined(values.swapAssetFrom)) return await setFieldValue('swapAssetFrom', swappableAssetsFrom[0]); diff --git a/src/app/pages/transaction-request/transaction-request.tsx b/src/app/pages/transaction-request/transaction-request.tsx index 55aea73d0dd..c521a116292 100644 --- a/src/app/pages/transaction-request/transaction-request.tsx +++ b/src/app/pages/transaction-request/transaction-request.tsx @@ -1,4 +1,4 @@ -import { memo } from 'react'; +import { memo, useState } from 'react'; import { Outlet, useNavigate } from 'react-router-dom'; import { Formik, FormikHelpers } from 'formik'; @@ -13,13 +13,11 @@ import { RouteUrls } from '@shared/route-urls'; import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; import { useOnMount } from '@app/common/hooks/use-on-mount'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; import { stxFeeValidator } from '@app/common/validation/forms/fee-validators'; import { nonceValidator } from '@app/common/validation/nonce-validators'; import { NonceSetter } from '@app/components/nonce-setter'; -import { PopupHeader } from '@app/features/current-account/popup-header'; +import { HighFeeDialog } from '@app/features/dialogs/high-fee-dialog/high-fee-dialog'; import { RequestingTabClosedWarningMessage } from '@app/features/errors/requesting-tab-closed-error-msg'; -import { HighFeeDrawer } from '@app/features/high-fee-drawer/high-fee-drawer'; import { ContractCallDetails } from '@app/features/stacks-transaction-request/contract-call-details/contract-call-details'; import { ContractDeployDetails } from '@app/features/stacks-transaction-request/contract-deploy-details/contract-deploy-details'; import { FeeForm } from '@app/features/stacks-transaction-request/fee-form'; @@ -42,6 +40,8 @@ import { import { Link } from '@app/ui/components/link/link'; function TransactionRequestBase() { + const [isShowingHighFeeConfirmation, setIsShowingHighFeeConfirmation] = useState(false); + const transactionRequest = useTransactionRequestState(); const unsignedTx = useUnsignedStacksTransactionBaseState(); const { data: stxFees } = useCalculateStacksTxFees(unsignedTx.transaction); @@ -52,8 +52,6 @@ function TransactionRequestBase() { const navigate = useNavigate(); const { stacksBroadcastTransaction } = useStacksBroadcastTransaction('STX'); - useRouteHeader(); - useOnMount(() => void analytics.track('view_transaction_signing')); async function onSubmit( @@ -119,8 +117,14 @@ function TransactionRequestBase() { Edit nonce - - + setIsShowingHighFeeConfirmation(true)} + /> + + )} diff --git a/src/app/pages/unlock.tsx b/src/app/pages/unlock.tsx index 71135790040..8906f5f5b98 100644 --- a/src/app/pages/unlock.tsx +++ b/src/app/pages/unlock.tsx @@ -1,56 +1,17 @@ -import { useEffect } from 'react'; import { Outlet, useNavigate } from 'react-router-dom'; -import { Box } from 'leather-styles/jsx'; - -import { WALLET_ENVIRONMENT } from '@shared/environment'; import { RouteUrls } from '@shared/route-urls'; -import { closeWindow } from '@shared/utils'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; -import { isFullPageMode, isPopupMode } from '@app/common/utils'; -import { openIndexPageInNewTab } from '@app/common/utils/open-in-new-tab'; -import { Header } from '@app/components/header'; import { RequestPassword } from '@app/components/request-password'; -import { useNewBrandApprover } from '@app/store/settings/settings.selectors'; export function Unlock() { const navigate = useNavigate(); - useRouteHeader(
    ); - - const { hasApprovedNewBrand } = useNewBrandApprover(); - - useEffect(() => { - if (!hasApprovedNewBrand && isPopupMode() && WALLET_ENVIRONMENT !== 'testing') { - openIndexPageInNewTab('/unlock/we-have-a-new-name'); - closeWindow(); - } - if (!hasApprovedNewBrand && isFullPageMode()) { - navigate('./we-have-a-new-name'); - } - }, [hasApprovedNewBrand, navigate]); - const handleSuccess = () => navigate(RouteUrls.Home); return ( <> - {/* Hide the logo when user hasn't consented yet */} - {!hasApprovedNewBrand && ( - - )} - - - Your -
    - session is locked - - } - caption="Enter the password you set on this device" - onSuccess={handleSuccess} - /> + ); diff --git a/src/app/pages/update-profile-request/update-profile-request.tsx b/src/app/pages/update-profile-request/update-profile-request.tsx index 44602f339bf..3369a3f4440 100644 --- a/src/app/pages/update-profile-request/update-profile-request.tsx +++ b/src/app/pages/update-profile-request/update-profile-request.tsx @@ -2,8 +2,6 @@ import { memo } from 'react'; import { closeWindow, isUndefined } from '@shared/utils'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; -import { PopupHeader } from '@app/features/current-account/popup-header'; import { useOnOriginTabClose } from '@app/routes/hooks/use-on-tab-closed'; import { useIsProfileUpdateRequestValid, @@ -18,8 +16,6 @@ function ProfileUpdateRequestBase() { const validProfileUpdateRequest = useIsProfileUpdateRequestValid(); const { requestToken } = useProfileUpdateRequestSearchParams(); - useRouteHeader(); - useOnOriginTabClose(() => closeWindow()); if (isUndefined(validProfileUpdateRequest) || !validProfileUpdateRequest || !requestToken) return ( diff --git a/src/app/pages/view-secret-key/components/view-secret-key.content.tsx b/src/app/pages/view-secret-key/components/view-secret-key.content.tsx deleted file mode 100644 index ea124ff4a10..00000000000 --- a/src/app/pages/view-secret-key/components/view-secret-key.content.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { styled } from 'leather-styles/jsx'; - -export function ViewSecretKeyContent(): React.JSX.Element { - return ( - <> - - Your
    Secret Key -
    - - These 24 words are your Secret Key. They create your account, and you sign in on different - devices with them. Make sure to save these somewhere safe. - - -
    - - If you lose these words, you lose your account. - - - ); -} diff --git a/src/app/pages/view-secret-key/view-secret-key.tsx b/src/app/pages/view-secret-key/view-secret-key.tsx index 5921326d62b..f2e0684848d 100644 --- a/src/app/pages/view-secret-key/view-secret-key.tsx +++ b/src/app/pages/view-secret-key/view-secret-key.tsx @@ -1,26 +1,17 @@ import { useEffect, useState } from 'react'; -import { Outlet, useNavigate } from 'react-router-dom'; - -import { RouteUrls } from '@shared/route-urls'; +import { Outlet } from 'react-router-dom'; import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; -import { useRouteHeader } from '@app/common/hooks/use-route-header'; -import { Header } from '@app/components/header'; import { RequestPassword } from '@app/components/request-password'; -import { TwoColumnLayout } from '@app/components/secret-key/two-column.layout'; -import { SecretKeyDisplayer } from '@app/features/secret-key-displayer/secret-key-displayer'; +import { SecretKey } from '@app/features/secret-key-displayer/secret-key-displayer'; import { useDefaultWalletSecretKey } from '@app/store/in-memory-key/in-memory-key.selectors'; - -import { ViewSecretKeyContent } from './components/view-secret-key.content'; +import { TwoColumnLayout } from '@app/ui/pages/two-column.layout'; export function ViewSecretKey() { const analytics = useAnalytics(); - const navigate = useNavigate(); const defaultWalletSecretKey = useDefaultWalletSecretKey(); const [showSecretKey, setShowSecretKey] = useState(false); - useRouteHeader(
    navigate(RouteUrls.Home)} />); - useEffect(() => { void analytics.page('view', '/save-secret-key'); }, [analytics]); @@ -28,25 +19,28 @@ export function ViewSecretKey() { if (showSecretKey) { return ( } - rightColumn={} - /> - ); - } - - return ( - <> - - View + Your
    Secret Key + + } + content={ + <> + These 24 words are your Secret Key. They create your account, and you sign in on + different devices with them. Make sure to save these somewhere safe.
    - Secret Key + If you lose these words, you lose your account. } - caption="Enter the password you set on this device" - onSuccess={() => setShowSecretKey(true)} - /> + > + +
    + ); + } + + return ( + <> + setShowSecretKey(true)} /> ); diff --git a/src/app/routes/app-routes.tsx b/src/app/routes/app-routes.tsx index d53359792b8..5e5e2359d68 100644 --- a/src/app/routes/app-routes.tsx +++ b/src/app/routes/app-routes.tsx @@ -12,11 +12,11 @@ import { RouteUrls } from '@shared/route-urls'; import { LoadingSpinner } from '@app/components/loading-spinner'; import { AddNetwork } from '@app/features/add-network/add-network'; import { Container } from '@app/features/container/container'; -import { EditNonceDrawer } from '@app/features/edit-nonce-drawer/edit-nonce-drawer'; -import { IncreaseBtcFeeDrawer } from '@app/features/increase-fee-drawer/increase-btc-fee-drawer'; -import { IncreaseFeeSentDrawer } from '@app/features/increase-fee-drawer/increase-fee-sent-drawer'; -import { IncreaseStxFeeDrawer } from '@app/features/increase-fee-drawer/increase-stx-fee-drawer'; -import { leatherIntroDialogRoutes } from '@app/features/leather-intro-dialog/leather-intro-dialog'; +import { EditNonceDialog } from '@app/features/dialogs/edit-nonce-dialog/edit-nonce-dialog'; +import { IncreaseBtcFeeDialog } from '@app/features/dialogs/increase-fee-dialog/increase-btc-fee-dialog'; +import { IncreaseFeeSentDialog } from '@app/features/dialogs/increase-fee-dialog/increase-fee-sent-dialog'; +import { IncreaseStxFeeDialog } from '@app/features/dialogs/increase-fee-dialog/increase-stx-fee-dialog'; +import { leatherIntroDialogRoutes } from '@app/features/dialogs/leather-intro-dialog/leather-intro-dialog'; import { ledgerBitcoinTxSigningRoutes } from '@app/features/ledger/flows/bitcoin-tx-signing/ledger-bitcoin-sign-tx-container'; import { ledgerJwtSigningRoutes } from '@app/features/ledger/flows/jwt-signing/ledger-sign-jwt.routes'; import { requestBitcoinKeysRoutes } from '@app/features/ledger/flows/request-bitcoin-keys/ledger-request-bitcoin-keys'; @@ -51,7 +51,6 @@ import { AccountGate } from '@app/routes/account-gate'; import { receiveRoutes } from '@app/routes/receive-routes'; import { legacyRequestRoutes } from '@app/routes/request-routes'; import { rpcRequestRoutes } from '@app/routes/rpc-routes'; -import { settingsRoutes } from '@app/routes/settings-routes'; import { OnboardingGate } from './onboarding-gate'; @@ -66,7 +65,6 @@ export function AppRoutes() { export const homePageModalRoutes = ( <> - {settingsRoutes} {receiveRoutes} {ledgerStacksTxSigningRoutes} {ledgerBitcoinTxSigningRoutes} @@ -92,13 +90,13 @@ function useAppRoutes() { } /> - }> + }> {ledgerStacksTxSigningRoutes} - }> + }> {ledgerBitcoinTxSigningRoutes} - } /> + } /> {ledgerStacksTxSigningRoutes} @@ -183,8 +181,6 @@ function useAppRoutes() { } > - {settingsRoutes} - } /> } /> @@ -196,7 +192,6 @@ function useAppRoutes() { } > - {settingsRoutes} } /> @@ -209,11 +204,8 @@ function useAppRoutes() { } - > - {settingsRoutes} - + /> }> - {settingsRoutes} {leatherIntroDialogRoutes} @@ -237,7 +229,7 @@ function useAppRoutes() { } > - } /> + } /> - } /> + } /> } /> } /> } /> - } /> + } /> } /> ); diff --git a/src/app/routes/request-routes.tsx b/src/app/routes/request-routes.tsx index 1b0e931009b..1cd1886af83 100644 --- a/src/app/routes/request-routes.tsx +++ b/src/app/routes/request-routes.tsx @@ -3,8 +3,8 @@ import { Route } from 'react-router-dom'; import { RouteUrls } from '@shared/route-urls'; -import { BroadcastErrorDrawer } from '@app/components/broadcast-error-drawer/broadcast-error-drawer'; -import { EditNonceDrawer } from '@app/features/edit-nonce-drawer/edit-nonce-drawer'; +import { BroadcastErrorDialog } from '@app/components/broadcast-error-dialog/broadcast-error-dialog'; +import { EditNonceDialog } from '@app/features/dialogs/edit-nonce-dialog/edit-nonce-dialog'; import { ledgerStacksMessageSigningRoutes } from '@app/features/ledger/flows/stacks-message-signing/ledger-stacks-sign-msg.routes'; import { ledgerStacksTxSigningRoutes } from '@app/features/ledger/flows/stacks-tx-signing/ledger-sign-stacks-tx-container'; import { PsbtRequest } from '@app/pages/psbt-request/psbt-request'; @@ -27,8 +27,8 @@ export const legacyRequestRoutes = ( } > {ledgerStacksTxSigningRoutes} - } /> - } /> + } /> + } /> - } /> - } /> - } /> - -); diff --git a/src/app/store/networks/networks.ts b/src/app/store/networks/networks.ts index 71e3b192529..db70acf03de 100644 --- a/src/app/store/networks/networks.ts +++ b/src/app/store/networks/networks.ts @@ -9,6 +9,8 @@ import { storeAtom } from '..'; import { selectCurrentNetworkId, selectNetworks } from './networks.selectors'; import { findMatchingNetworkKey } from './networks.utils'; +// TODO as about this as it's depreacted but not sure what to do instead +// PR https://github.com/leather-wallet/extension/pull/3017 /** @deprecated */ export const currentNetworkAtom = atom(get => { const store = get(storeAtom); diff --git a/src/app/store/settings/settings.selectors.ts b/src/app/store/settings/settings.selectors.ts index 34862abfb69..4103be10dda 100644 --- a/src/app/store/settings/settings.selectors.ts +++ b/src/app/store/settings/settings.selectors.ts @@ -2,9 +2,7 @@ import { useSelector } from 'react-redux'; import { createSelector } from '@reduxjs/toolkit'; -import { RootState, useAppDispatch } from '@app/store'; - -import { settingsSlice } from './settings.slice'; +import { RootState } from '@app/store'; const selectSettings = (state: RootState) => state.settings; @@ -40,19 +38,3 @@ const selectDismissedMessageIds = createSelector( export function useDismissedMessageIds() { return useSelector(selectDismissedMessageIds); } - -const selectHasApprovedNewBrand = createSelector( - selectSettings, - state => !!state.hasApprovedNewBrand -); - -export function useNewBrandApprover() { - const hasApprovedNewBrand = useSelector(selectHasApprovedNewBrand); - const dispatch = useAppDispatch(); - return { - hasApprovedNewBrand, - userApprovedNewBrand() { - dispatch(settingsSlice.actions.setHasApprovedNewBrand()); - }, - }; -} diff --git a/src/app/store/settings/settings.slice.ts b/src/app/store/settings/settings.slice.ts index be0960dca6a..36105a6b890 100644 --- a/src/app/store/settings/settings.slice.ts +++ b/src/app/store/settings/settings.slice.ts @@ -7,15 +7,12 @@ interface InitialState { userSelectedTheme: UserSelectedTheme; hasAllowedAnalytics: HasAcceptedAnalytics; dismissedMessages: string[]; - hasApprovedNewBrand: boolean; } const initialState: InitialState = { userSelectedTheme: 'system', hasAllowedAnalytics: null, dismissedMessages: [], - // Defaults to true, as this is undefined for existing users - hasApprovedNewBrand: true, }; export const settingsSlice = createSlice({ @@ -35,11 +32,5 @@ export const settingsSlice = createSlice({ resetMessages(state) { state.dismissedMessages = []; }, - setHasApprovedNewBrand(state) { - state.hasApprovedNewBrand = true; - }, - resetHasApprovedNewBrand(state) { - state.hasApprovedNewBrand = false; - }, }, }); diff --git a/src/app/store/ui/ui.hooks.ts b/src/app/store/ui/ui.hooks.ts index e8344c96800..bde03bc5c23 100644 --- a/src/app/store/ui/ui.hooks.ts +++ b/src/app/store/ui/ui.hooks.ts @@ -1,30 +1,6 @@ import { useAtom } from 'jotai'; -import { - errorStackTraceState, - loadingState, - routeHeaderState, - showHighFeeConfirmationState, - showSettingsStore, - showSwitchAccountsState, - showTxSettingsCallback, -} from './ui'; - -export function useShowHighFeeConfirmationState() { - return useAtom(showHighFeeConfirmationState); -} - -export function useShowSwitchAccountsState() { - return useAtom(showSwitchAccountsState); -} - -export function useShowSettingsStore() { - return useAtom(showSettingsStore); -} - -export function useShowTxSettingsCallback() { - return useAtom(showTxSettingsCallback); -} +import { errorStackTraceState, loadingState } from './ui'; export function useLoadingState(key: string) { return useAtom(loadingState(key)); @@ -33,7 +9,3 @@ export function useLoadingState(key: string) { export function useErrorStackTraceState() { return useAtom(errorStackTraceState); } - -export function useRouteHeaderState() { - return useAtom(routeHeaderState); -} diff --git a/src/app/store/ui/ui.ts b/src/app/store/ui/ui.ts index bbcd2eaa5f6..ea1ad46c9c9 100644 --- a/src/app/store/ui/ui.ts +++ b/src/app/store/ui/ui.ts @@ -9,15 +9,4 @@ export const loadingState = atomFamily(_param => { return anAtom; }); -// TODO: refactor into atom family -export const showSwitchAccountsState = atom(false); - -export const showHighFeeConfirmationState = atom(false); - -export const showSettingsStore = atom(false); - -export const showTxSettingsCallback = atom<(() => Promise) | undefined>(undefined); - export const errorStackTraceState = atom(null); - -export const routeHeaderState = atom(null); diff --git a/src/app/components/account/account-avatar-item.tsx b/src/app/ui/components/account/account-avatar/account-avatar-item.tsx similarity index 76% rename from src/app/components/account/account-avatar-item.tsx rename to src/app/ui/components/account/account-avatar/account-avatar-item.tsx index a6470aca3de..f0b4ecdfa59 100644 --- a/src/app/components/account/account-avatar-item.tsx +++ b/src/app/ui/components/account/account-avatar/account-avatar-item.tsx @@ -1,6 +1,6 @@ import { memo } from 'react'; -import { AccountAvatar } from '@app/components/account/account-avatar'; +import { AccountAvatar } from '@app/ui/components/account/account-avatar/account-avatar'; interface AccountAvatarItemProps { publicKey: string; diff --git a/src/app/components/account/account-avatar.tsx b/src/app/ui/components/account/account-avatar/account-avatar.tsx similarity index 100% rename from src/app/components/account/account-avatar.tsx rename to src/app/ui/components/account/account-avatar/account-avatar.tsx diff --git a/src/app/ui/components/account/account.card.stories.tsx b/src/app/ui/components/account/account.card.stories.tsx new file mode 100644 index 00000000000..8ae4327afc7 --- /dev/null +++ b/src/app/ui/components/account/account.card.stories.tsx @@ -0,0 +1,33 @@ +import type { Meta } from '@storybook/react'; +import { Flex } from 'leather-styles/jsx'; + +import { ActionButton } from '@app/ui/components/account/action-button'; +import { ArrowDownIcon, ArrowUpIcon, PlusIcon, SwapIcon } from '@app/ui/icons'; + +import { AccountCard as Component } from './account.card'; + +const meta: Meta = { + component: Component, + tags: ['autodocs'], + title: 'Design System/Layout/AccountCard', +}; + +export default meta; + +export function AccountCard() { + return ( + } + toggleSwitchAccount={() => null} + > + + } label="Send" /> + } label="Receive" /> + } label="Buy" /> + } label="Swap" /> + + + ); +} diff --git a/src/app/ui/components/account/account.card.tsx b/src/app/ui/components/account/account.card.tsx new file mode 100644 index 00000000000..ffda04dada1 --- /dev/null +++ b/src/app/ui/components/account/account.card.tsx @@ -0,0 +1,66 @@ +import { ReactNode } from 'react'; + +import { SettingsSelectors } from '@tests/selectors/settings.selectors'; +import { Box, Divider, Flex, styled } from 'leather-styles/jsx'; + +import { Link } from '@app/ui/components/link/link'; +import { ChevronDownIcon } from '@app/ui/icons'; + +interface AccountCardProps { + name: string; + balance: string; + children: ReactNode; + switchAccount: ReactNode; + toggleSwitchAccount(): void; +} + +export function AccountCard({ + name, + balance, + switchAccount, + toggleSwitchAccount, + children, +}: AccountCardProps) { + return ( + + + + + {name} + + + + + + + + + {balance} + + + {switchAccount} + + {children} + + + ); +} diff --git a/src/app/pages/home/components/action-button.tsx b/src/app/ui/components/account/action-button.tsx similarity index 63% rename from src/app/pages/home/components/action-button.tsx rename to src/app/ui/components/account/action-button.tsx index 0c1234c0f80..085b2a51562 100644 --- a/src/app/pages/home/components/action-button.tsx +++ b/src/app/ui/components/account/action-button.tsx @@ -1,9 +1,8 @@ import { Flex, styled } from 'leather-styles/jsx'; +import AccessibleIcon from '@app/ui/components/avatar-icon/accessible-icon'; import { Button } from '@app/ui/components/button/button'; -import AccessibleIcon from './accessible-icon'; - interface ActionButtonProps extends React.ComponentProps { icon: React.ReactNode; label: string; @@ -11,10 +10,17 @@ interface ActionButtonProps extends React.ComponentProps { export function ActionButton({ icon, label, ...rest }: ActionButtonProps) { return ( - ); diff --git a/src/app/pages/home/components/accessible-icon.tsx b/src/app/ui/components/avatar-icon/accessible-icon.tsx similarity index 100% rename from src/app/pages/home/components/accessible-icon.tsx rename to src/app/ui/components/avatar-icon/accessible-icon.tsx diff --git a/src/app/ui/components/bullet-separator/bullet-separator.tsx b/src/app/ui/components/bullet-separator/bullet-separator.tsx index 9d6c7f1213e..a403ed1e79e 100644 --- a/src/app/ui/components/bullet-separator/bullet-separator.tsx +++ b/src/app/ui/components/bullet-separator/bullet-separator.tsx @@ -7,7 +7,7 @@ export function BulletOperator(props: CircleProps) { = { @@ -39,34 +40,6 @@ export const Disabled: Story = { }, }; -// TODO: Remove invert code -export const InvertSolid: Story = { - parameters: { - backgrounds: { default: 'leather-dark-mode' }, - controls: { include: [] }, - }, - args: { - children: 'Button', - invert: true, - size: 'md', - variant: 'solid', - }, -}; - -// TODO: Remove invert code -export const InvertOutline: Story = { - parameters: { - backgrounds: { default: 'leather-dark-mode' }, - controls: { include: [] }, - }, - args: { - children: 'Button', - invert: true, - size: 'md', - variant: 'outline', - }, -}; - export const WithIcons: Story = { parameters: { controls: { include: ['size', 'variant'] }, diff --git a/src/app/ui/components/button/button.tsx b/src/app/ui/components/button/button.tsx index e7bd05cb093..8c521b60dac 100644 --- a/src/app/ui/components/button/button.tsx +++ b/src/app/ui/components/button/button.tsx @@ -7,10 +7,11 @@ type ButtonProps = Omit, keyof ButtonV ButtonVariantProps; export function Button(props: ButtonProps) { - const { children, fullWidth, invert, size, trigger, type = 'button', variant, ...rest } = props; + const { children, fullWidth, size, trigger, invert, type = 'button', variant, ...rest } = props; + // pete - not sure we need this invert but it could be thje key difference return ( diff --git a/src/app/ui/components/containers/container.layout.tsx b/src/app/ui/components/containers/container.layout.tsx new file mode 100644 index 00000000000..87f039aad96 --- /dev/null +++ b/src/app/ui/components/containers/container.layout.tsx @@ -0,0 +1,30 @@ +import { radixBaseCSS } from '@radix-ui/themes/styles.css'; +import { css } from 'leather-styles/css'; +import { Flex } from 'leather-styles/jsx'; + +interface ContainerLayoutProps { + children: React.JSX.Element | React.JSX.Element[]; + header: React.JSX.Element | null; + variant: string; +} +// better to keep this component for use in storybook demos +export function ContainerLayout({ children, header, variant }: ContainerLayoutProps) { + // no header still needs to have space I think - check on landing pages + return ( + + {header} + + {children} + + + ); +} diff --git a/src/app/ui/components/containers/dialog/dialog.stories.tsx b/src/app/ui/components/containers/dialog/dialog.stories.tsx new file mode 100644 index 00000000000..db0b1f5f8d9 --- /dev/null +++ b/src/app/ui/components/containers/dialog/dialog.stories.tsx @@ -0,0 +1,15 @@ +import type { Meta } from '@storybook/react'; + +import { Dialog as Component, RadixDialogProps } from './dialog'; + +const meta: Meta = { + component: Component, + tags: ['autodocs'], + title: 'Design System/Containers/Dialog', +}; + +export default meta; + +export function Dialog(args: RadixDialogProps) { + return ; +} diff --git a/src/app/ui/components/containers/dialog/dialog.tsx b/src/app/ui/components/containers/dialog/dialog.tsx new file mode 100644 index 00000000000..85a99efa421 --- /dev/null +++ b/src/app/ui/components/containers/dialog/dialog.tsx @@ -0,0 +1,61 @@ +import { JSXElementConstructor, ReactElement, ReactNode, cloneElement } from 'react'; + +import * as RadixDialog from '@radix-ui/react-dialog'; +import { css } from 'leather-styles/css'; + +import { CardContent } from '@app/ui/layout/card/card-content'; + +export interface DialogProps { + isShowing: boolean; + onClose(): void; +} +export interface RadixDialogProps extends DialogProps { + children: ReactNode; + footer?: ReactNode; + header?: ReactElement>; + onGoBack?(): void; +} + +export function Dialog({ children, footer, header, onClose, isShowing }: RadixDialogProps) { + if (!isShowing) return null; + + return ( + + + + + {header && cloneElement(header, { onClose })} + + {children} + {footer} + + + + + ); +} diff --git a/src/app/components/available-balance.tsx b/src/app/ui/components/containers/footers/available-balance.tsx similarity index 62% rename from src/app/components/available-balance.tsx rename to src/app/ui/components/containers/footers/available-balance.tsx index 864b7ef15a8..37d9041d638 100644 --- a/src/app/components/available-balance.tsx +++ b/src/app/ui/components/containers/footers/available-balance.tsx @@ -1,17 +1,17 @@ import { Box, Flex, HStack, styled } from 'leather-styles/jsx'; -import { Money } from '@shared/models/money.model'; - -import { formatMoney } from '@app/common/money/format-money'; import { BasicTooltip } from '@app/ui/components/tooltip/basic-tooltip'; import { InfoCircleIcon } from '@app/ui/icons/info-circle-icon'; -export function AvailableBalance(props: { balance: Money; balanceTooltipLabel?: string }) { - const { - balance, - balanceTooltipLabel = 'Amount that is immediately available for use after taking into account any pending transactions or holds placed on your account by the protocol.', - } = props; +interface AvailableBalanceProps { + balance: string; + balanceTooltipLabel?: string; +} +export function AvailableBalance({ + balance, + balanceTooltipLabel = 'Amount that is immediately available for use after taking into account any pending transactions or holds placed on your account by the protocol.', +}: AvailableBalanceProps) { return ( @@ -25,7 +25,7 @@ export function AvailableBalance(props: { balance: Money; balanceTooltipLabel?: - {formatMoney(balance)} + {balance} ); diff --git a/src/app/ui/components/containers/footers/footer.stories.tsx b/src/app/ui/components/containers/footers/footer.stories.tsx new file mode 100644 index 00000000000..e4c58026b88 --- /dev/null +++ b/src/app/ui/components/containers/footers/footer.stories.tsx @@ -0,0 +1,153 @@ +import type { Meta } from '@storybook/react'; +import { Flex, styled } from 'leather-styles/jsx'; + +import { Button } from '@app/ui/components/button/button'; +import { AvailableBalance } from '@app/ui/components/containers/footers/available-balance'; + +import { Footer as Component } from './footer'; + +const meta: Meta = { + component: Component, + tags: ['autodocs'], + title: 'Design System/Containers/Footer', + parameters: { + controls: { + disable: true, + // TODO try get rid of these empty controls + // https://github.com/storybookjs/storybook/issues/24422 + hideNoControlsWarning: true, + }, + }, +}; + +export default meta; + +export function Footer() { + return ( + + + + ); +} + +export function SignOutConfirmFooter() { + return ( + + + + + + + ); +} + +export function ReceiveTokensFooter() { + return ( + + + + ); +} + +export function RequestPasswordFooter() { + return ( + + + + ); +} + +export function FooterWithText() { + return ( + + + + + + Leather Wallet will now be provided by Leather Wallet LLC [a subsidiary of Nassau Machines + Inc]. Please review and accept Leather Wallet{' '} + + Terms of Service + {' '} + and{' '} + + Privacy Policy + + . + + + + ); +} + +export function FooterWithLink() { + return ( + + + + + {/* use new + View all addresses + + + + ); +} + +export function FooterWithBalance() { + return ( + + + + + ); +} + +export function FooterWithBalancesAbove() { + return ( + + + 0.00048208 BTC + $ 1,100.00 + + + + ); +} diff --git a/src/app/ui/components/containers/footers/footer.tsx b/src/app/ui/components/containers/footers/footer.tsx new file mode 100644 index 00000000000..ef1668a3d2e --- /dev/null +++ b/src/app/ui/components/containers/footers/footer.tsx @@ -0,0 +1,32 @@ +import type { ReactNode } from 'react'; + +import { Flex, styled } from 'leather-styles/jsx'; + +interface FooterProps { + children: ReactNode; + variant?: 'page' | 'card'; + flexDirection?: 'column' | 'row'; +} + +export function Footer({ children, variant = 'page', flexDirection = 'column' }: FooterProps) { + return ( + + + {children} + + + ); +} diff --git a/src/app/ui/components/containers/headers/components/network-mode-badge.tsx b/src/app/ui/components/containers/headers/components/network-mode-badge.tsx new file mode 100644 index 00000000000..a9dfa731c82 --- /dev/null +++ b/src/app/ui/components/containers/headers/components/network-mode-badge.tsx @@ -0,0 +1,27 @@ +import { Flex, styled } from 'leather-styles/jsx'; + +interface NetworkModeBadge { + isTestnetChain: boolean; + name: string; +} + +export function NetworkModeBadge({ isTestnetChain, name }: NetworkModeBadge) { + if (!isTestnetChain) return null; + + // TODO #4794: replace with design system tag + return ( + + + {name} + + + ); +} diff --git a/src/app/components/drawer/components/header-action-button.tsx b/src/app/ui/components/containers/headers/header-action-button.tsx similarity index 62% rename from src/app/components/drawer/components/header-action-button.tsx rename to src/app/ui/components/containers/headers/header-action-button.tsx index 3fa5c4308a0..b8672c118cf 100644 --- a/src/app/components/drawer/components/header-action-button.tsx +++ b/src/app/ui/components/containers/headers/header-action-button.tsx @@ -1,34 +1,36 @@ import { HomePageSelectors } from '@tests/selectors/home.selectors'; -import { Grid } from 'leather-styles/jsx'; +import { Flex, FlexProps } from 'leather-styles/jsx'; -interface HeaderActionButtonProps { +interface HeaderActionButtonProps extends FlexProps { icon?: React.JSX.Element; isWaitingOnPerformedAction?: boolean; onAction?(): void; } -export function HeaderActionButton(props: HeaderActionButtonProps) { - const { icon, isWaitingOnPerformedAction, onAction } = props; - +export function HeaderActionButton({ + icon, + isWaitingOnPerformedAction, + onAction, + ...rest +}: HeaderActionButtonProps) { return ( - {icon} - + ); } diff --git a/src/app/ui/components/containers/headers/header.stories.tsx b/src/app/ui/components/containers/headers/header.stories.tsx new file mode 100644 index 00000000000..f64a44fd9cb --- /dev/null +++ b/src/app/ui/components/containers/headers/header.stories.tsx @@ -0,0 +1,22 @@ +import type { Meta } from '@storybook/react'; + +import { Header as Component, HeaderProps } from './header'; + +const meta: Meta = { + component: Component, + tags: ['autodocs'], + title: 'Design System/Containers/Header', + args: { + variant: 'home', + }, +}; + +export default meta; + +export function Header(args: HeaderProps) { + return null} onGoBack={() => null} />; +} + +export function PageHeader(args: HeaderProps) { + return null} />; +} diff --git a/src/app/ui/components/containers/headers/header.tsx b/src/app/ui/components/containers/headers/header.tsx new file mode 100644 index 00000000000..92b1a42de7d --- /dev/null +++ b/src/app/ui/components/containers/headers/header.tsx @@ -0,0 +1,86 @@ +import { ReactNode } from 'react'; + +import { SharedComponentsSelectors } from '@tests/selectors/shared-component.selectors'; +import { Flex, Grid, GridItem, HStack, styled } from 'leather-styles/jsx'; + +import { ArrowLeftIcon, CloseIcon } from '@app/ui/icons'; + +import { HeaderActionButton } from './header-action-button'; + +export interface HeaderProps { + variant: 'page' | 'home' | 'onboarding' | 'dialog' | 'receive'; + isWaitingOnPerformedAction?: boolean; + onClose?(): void; + onGoBack?(): void; + title?: ReactNode; + account?: ReactNode; + totalBalance?: ReactNode; + settingsMenu?: ReactNode; + networkBadge?: ReactNode; + logo?: ReactNode; +} + +export function Header({ + variant, + isWaitingOnPerformedAction, + onClose, + onGoBack, + account, + totalBalance, + settingsMenu, + networkBadge, + title, + logo, +}: HeaderProps) { + const logoItem = onGoBack || logo || account; + return ( + + + + {logoItem && ( + + {variant !== 'home' && onGoBack ? ( + } + isWaitingOnPerformedAction={isWaitingOnPerformedAction} + onAction={onGoBack} + hideFrom={variant === 'receive' ? 'md' : undefined} + /> + ) : undefined} + {account ? account : logo} + + )} + + + {title && {title}} + + + + {networkBadge} + {totalBalance} + {variant !== 'onboarding' && settingsMenu} + + {onClose && ( + } + isWaitingOnPerformedAction={isWaitingOnPerformedAction} + onAction={onClose} + hideBelow={variant === 'receive' ? 'md' : undefined} + /> + )} + + + + + ); +} diff --git a/src/app/ui/components/containers/popup/popup-card.tsx b/src/app/ui/components/containers/popup/popup-card.tsx new file mode 100644 index 00000000000..5a51fc3513b --- /dev/null +++ b/src/app/ui/components/containers/popup/popup-card.tsx @@ -0,0 +1,21 @@ +import { Stack } from 'leather-styles/jsx'; + +import { HasChildren } from '@app/common/has-children'; + +export function PopupCard({ children }: HasChildren) { + return ( + + {children} + + ); +} diff --git a/src/app/ui/components/dowpdown-menu/dropdown-menu-item.layout.tsx b/src/app/ui/components/dropdown-menu/dropdown-menu-item.layout.tsx similarity index 100% rename from src/app/ui/components/dowpdown-menu/dropdown-menu-item.layout.tsx rename to src/app/ui/components/dropdown-menu/dropdown-menu-item.layout.tsx diff --git a/src/app/ui/components/dowpdown-menu/dropdown-menu.stories.tsx b/src/app/ui/components/dropdown-menu/dropdown-menu.stories.tsx similarity index 100% rename from src/app/ui/components/dowpdown-menu/dropdown-menu.stories.tsx rename to src/app/ui/components/dropdown-menu/dropdown-menu.stories.tsx diff --git a/src/app/ui/components/dowpdown-menu/dropdown-menu.tsx b/src/app/ui/components/dropdown-menu/dropdown-menu.tsx similarity index 73% rename from src/app/ui/components/dowpdown-menu/dropdown-menu.tsx rename to src/app/ui/components/dropdown-menu/dropdown-menu.tsx index e53cdf06634..981cab44095 100644 --- a/src/app/ui/components/dowpdown-menu/dropdown-menu.tsx +++ b/src/app/ui/components/dropdown-menu/dropdown-menu.tsx @@ -26,6 +26,7 @@ const dropdownButtonStyles = css({ userSelect: 'none', '[data-state=open] &': { bg: 'ink.component-background-pressed' }, }); + function Button({ children, ...props }: HTMLStyledProps<'div'>) { return ( @@ -36,9 +37,21 @@ function Button({ children, ...props }: HTMLStyledProps<'div'>) { ); } +const dropdownIconButtonStyles = css({ + _hover: { bg: 'ink.component-background-hover' }, + _focus: { outline: 'none' }, + p: 'space.02', + + '&[data-state=open]': { bg: 'ink.component-background-pressed' }, +}); +const IconButton: typeof RadixDropdownMenu.Trigger = forwardRef((props, ref) => ( + +)); + const dropdownTriggerStyles = css({ _focus: { outline: 'none' }, }); + const Trigger: typeof RadixDropdownMenu.Trigger = forwardRef((props, ref) => ( )); @@ -50,14 +63,18 @@ const dropdownContentStyles = css({ borderRadius: 'xs', boxShadow: '0px 12px 24px 0px rgba(18, 16, 15, 0.08), 0px 4px 8px 0px rgba(18, 16, 15, 0.08), 0px 0px 2px 0px rgba(18, 16, 15, 0.08)', - p: 'space.02', + p: '0', willChange: 'transform, opacity', zIndex: 999, - _closed: { animation: 'slideDownAndOut 140ms ease-in-out' }, - _open: { animation: 'slideUpAndFade 140ms ease-in-out' }, + // _closed: { animation: 'slideDownAndOut 140ms ease-in-out' }, + // _open: { animation: 'slideUpAndFade 140ms ease-in-out' }); -const Content: typeof RadixDropdownMenu.Content = forwardRef((props, ref) => ( - +const Content: typeof RadixDropdownMenu.Content = forwardRef(({ className, ...props }, ref) => ( + )); const dropdownMenuLabelStyles = css({ @@ -92,6 +109,12 @@ const dropdownMenuSeparatorStyles = css({ const Separator: typeof RadixDropdownMenu.Separator = forwardRef((props, ref) => ( )); +const dropdownMenuGroupStyles = css({ + p: 'space.02', +}); +const Group: typeof RadixDropdownMenu.Group = forwardRef((props, ref) => ( + +)); export const DropdownMenu = { Root: RadixDropdownMenu.Root, @@ -99,6 +122,11 @@ export const DropdownMenu = { Portal: RadixDropdownMenu.Portal, Trigger, Button, + Portal: RadixDropdownMenu.Portal, + Group, + Trigger, + Button, + IconButton, Content, Label, Item, diff --git a/src/app/ui/components/flag/flag.stories.tsx b/src/app/ui/components/flag/flag.stories.tsx index b1f80906d52..2982ea3af10 100644 --- a/src/app/ui/components/flag/flag.stories.tsx +++ b/src/app/ui/components/flag/flag.stories.tsx @@ -18,7 +18,7 @@ const meta: Meta = { controls: { include: ['align'] }, }, render: ({ children, ...args }) => ( - }> + }> {children} ), @@ -30,6 +30,6 @@ type Story = StoryObj; export const Flag: Story = { args: { - children: , + children: , }, }; diff --git a/src/app/ui/components/item/item.stories.tsx b/src/app/ui/components/item/item.stories.tsx index 7a118342b18..1790c19e145 100644 --- a/src/app/ui/components/item/item.stories.tsx +++ b/src/app/ui/components/item/item.stories.tsx @@ -15,11 +15,11 @@ type Story = StoryObj; export const Item: Story = { render: () => ( } - titleLeft={} - captionLeft={} - titleRight={} - captionRight={} + flagImg={} + titleLeft={} + captionLeft={} + titleRight={} + captionRight={} /> ), }; diff --git a/src/app/ui/components/link/link.stories.tsx b/src/app/ui/components/link/link.stories.tsx index 8048b8a5091..1baf4cfdf65 100644 --- a/src/app/ui/components/link/link.stories.tsx +++ b/src/app/ui/components/link/link.stories.tsx @@ -33,17 +33,3 @@ export const Disabled: Story = { variant: 'underlined', }, }; - -// TODO: Remove invert code -export const InvertLink: Story = { - parameters: { - backgrounds: { default: 'leather-dark-mode' }, - controls: { include: [] }, - }, - args: { - children: 'Link', - invert: true, - size: 'md', - variant: 'underlined', - }, -}; diff --git a/src/app/ui/components/link/link.tsx b/src/app/ui/components/link/link.tsx index 6890f139d90..bcbbd902449 100644 --- a/src/app/ui/components/link/link.tsx +++ b/src/app/ui/components/link/link.tsx @@ -9,7 +9,7 @@ type LinkProps = Omit, keyof LinkVariant LinkVariantProps; export const Link = forwardRef((props: LinkProps, ref: ForwardedRef) => { - const { children, disabled, fullWidth, invert, size, variant, ...rest } = props; + const { children, disabled, fullWidth, size, invert, variant, ...rest } = props; return ( + + + ); +} diff --git a/src/app/components/secret-key/mnemonic-key/mnemonic-word-input.tsx b/src/app/ui/components/secret-key/mnemonic-key/mnemonic-word-input.tsx similarity index 100% rename from src/app/components/secret-key/mnemonic-key/mnemonic-word-input.tsx rename to src/app/ui/components/secret-key/mnemonic-key/mnemonic-word-input.tsx diff --git a/src/app/components/secret-key/mnemonic-key/utils/error-handling.ts b/src/app/ui/components/secret-key/mnemonic-key/utils/error-handling.ts similarity index 100% rename from src/app/components/secret-key/mnemonic-key/utils/error-handling.ts rename to src/app/ui/components/secret-key/mnemonic-key/utils/error-handling.ts diff --git a/src/app/components/secret-key/mnemonic-key/utils/validation.ts b/src/app/ui/components/secret-key/mnemonic-key/utils/validation.ts similarity index 100% rename from src/app/components/secret-key/mnemonic-key/utils/validation.ts rename to src/app/ui/components/secret-key/mnemonic-key/utils/validation.ts diff --git a/src/app/ui/components/secret-key/secret-key-grid.tsx b/src/app/ui/components/secret-key/secret-key-grid.tsx new file mode 100644 index 00000000000..1082a2b62a6 --- /dev/null +++ b/src/app/ui/components/secret-key/secret-key-grid.tsx @@ -0,0 +1,20 @@ +import { Grid } from 'leather-styles/jsx'; + +interface SecretKeyGridProps { + children: React.ReactNode; +} +export function SecretKeyGrid({ children }: SecretKeyGridProps) { + return ( + + {children} + + ); +} diff --git a/src/app/features/secret-key-displayer/components/secret-key-word.tsx b/src/app/ui/components/secret-key/secret-key-word.tsx similarity index 93% rename from src/app/features/secret-key-displayer/components/secret-key-word.tsx rename to src/app/ui/components/secret-key/secret-key-word.tsx index 1fad76031f1..dca0d2b8f27 100644 --- a/src/app/features/secret-key-displayer/components/secret-key-word.tsx +++ b/src/app/ui/components/secret-key/secret-key-word.tsx @@ -12,7 +12,7 @@ export function SecretKeyWord({ word, num }: SecretKeyWordProps) { width="100%" gap="space.01" px="space.03" - backgroundColor="ink.component-background-default" + bg="ink.component-background-default" borderRadius="xs" > diff --git a/src/app/features/secret-key-displayer/secret-key-displayer.layout.tsx b/src/app/ui/components/secret-key/secret-key.layout.tsx similarity index 63% rename from src/app/features/secret-key-displayer/secret-key-displayer.layout.tsx rename to src/app/ui/components/secret-key/secret-key.layout.tsx index c7b30138e2a..651aa81a822 100644 --- a/src/app/features/secret-key-displayer/secret-key-displayer.layout.tsx +++ b/src/app/ui/components/secret-key/secret-key.layout.tsx @@ -2,29 +2,33 @@ import { useState } from 'react'; import { OnboardingSelectors } from '@tests/selectors/onboarding.selectors'; import { SettingsSelectors } from '@tests/selectors/settings.selectors'; -import { Flex, styled } from 'leather-styles/jsx'; +import { Flex, HStack, Stack, styled } from 'leather-styles/jsx'; import { Button } from '@app/ui/components/button/button'; import { CopyIcon } from '@app/ui/icons/copy-icon'; import { EyeIcon } from '@app/ui/icons/eye-icon'; import { EyeSlashIcon } from '@app/ui/icons/eye-slash-icon'; -import { SecretKeyGrid } from '../../components/secret-key/secret-key-grid'; -import { SecretKeyWord } from './components/secret-key-word'; +import { SecretKeyGrid } from './secret-key-grid'; +import { SecretKeyWord } from './secret-key-word'; -interface SecretKeyDisplayerLayoutProps { +interface SecretKeyLayoutProps { hasCopied: boolean; onCopyToClipboard(): void; secretKeyWords: string[] | undefined; showTitleAndIllustration: boolean; onBackedUpSecretKey(): void; } -export function SecretKeyDisplayerLayout(props: SecretKeyDisplayerLayoutProps) { - const { hasCopied, onCopyToClipboard, onBackedUpSecretKey, secretKeyWords } = props; +export function SecretKeyLayout({ + hasCopied, + onCopyToClipboard, + onBackedUpSecretKey, + secretKeyWords, +}: SecretKeyLayoutProps) { const [showSecretKey, setShowSecretKey] = useState(false); return ( - <> + {secretKeyWords?.map((word, index) => ( ))} - + - + ); } diff --git a/src/app/ui/icons/docs/icons.mdx b/src/app/ui/icons/docs/icons.mdx index 0cf54de7f4b..4c4154ecb70 100644 --- a/src/app/ui/icons/docs/icons.mdx +++ b/src/app/ui/icons/docs/icons.mdx @@ -20,7 +20,7 @@ import { iconsList } from './icons-list';
    -

    Default 24x24

    +

    Default 24x24

    {iconsList.map(item => { const IconComponent = Icon[item]; @@ -36,7 +36,7 @@ import { iconsList } from './icons-list';
    -

    Small 16x16

    +

    Small 16x16

    {iconsList.map(item => { const IconComponent = Icon[item]; diff --git a/src/app/ui/layout/card/card-content.tsx b/src/app/ui/layout/card/card-content.tsx new file mode 100644 index 00000000000..76d1e651177 --- /dev/null +++ b/src/app/ui/layout/card/card-content.tsx @@ -0,0 +1,22 @@ +import { css } from 'leather-styles/css'; +import { Box } from 'leather-styles/jsx'; + +import { HasChildren } from '@app/common/has-children'; + +// Content wrapper used in Dialog + SendCryptoLayout +export function CardContent({ children }: HasChildren) { + return ( + + {children} + + ); +} diff --git a/src/app/ui/layout/card/card.stories.tsx b/src/app/ui/layout/card/card.stories.tsx new file mode 100644 index 00000000000..1577cefc000 --- /dev/null +++ b/src/app/ui/layout/card/card.stories.tsx @@ -0,0 +1,30 @@ +import type { Meta } from '@storybook/react'; +import { Box } from 'leather-styles/jsx'; + +import { Button } from '@app/ui/components/button/button'; + +import { Card as Component } from './card'; + +const meta: Meta = { + component: Component, + tags: ['autodocs'], + title: 'Design System/Layout/Card', +}; + +export default meta; + +export function Card() { + return ( + null}> + Create new account + + } + > + + + ); +} diff --git a/src/app/ui/layout/card/card.tsx b/src/app/ui/layout/card/card.tsx new file mode 100644 index 00000000000..f8c1bcba901 --- /dev/null +++ b/src/app/ui/layout/card/card.tsx @@ -0,0 +1,26 @@ +import type { ReactNode } from 'react'; + +import { Flex, Stack, styled } from 'leather-styles/jsx'; + +interface CardProps { + action?: ReactNode; + children: ReactNode; + title?: ReactNode; + text?: string; +} + +export function Card({ action, children, title, text }: CardProps) { + return ( + + {(title || text) && ( + + {title} + {text && {text}} + {children} + + )} + {!title && children} + {action} + + ); +} diff --git a/src/app/ui/layout/page/page.layout.stories.tsx b/src/app/ui/layout/page/page.layout.stories.tsx new file mode 100644 index 00000000000..d6a29ae0f11 --- /dev/null +++ b/src/app/ui/layout/page/page.layout.stories.tsx @@ -0,0 +1,21 @@ +import type { Meta } from '@storybook/react'; + +import { Card } from '@app/ui/layout/card/card.stories'; + +import { Page as Component } from './page.layout'; + +const meta: Meta = { + component: Component, + tags: ['autodocs'], + title: 'Design System/Layout/Page', +}; + +export default meta; + +export function Page() { + return ( + + + + ); +} diff --git a/src/app/ui/layout/page/page.layout.tsx b/src/app/ui/layout/page/page.layout.tsx new file mode 100644 index 00000000000..fb8e16dc99b --- /dev/null +++ b/src/app/ui/layout/page/page.layout.tsx @@ -0,0 +1,24 @@ +import { type ReactNode } from 'react'; + +import { Box } from 'leather-styles/jsx'; + +interface PageProps { + children: ReactNode; + showLogo?: boolean; +} + +export function Page({ children }: PageProps) { + return ( + + {children} + + ); +} diff --git a/src/app/ui/pages/home.layout.stories.tsx b/src/app/ui/pages/home.layout.stories.tsx new file mode 100644 index 00000000000..6e7dc8f92bc --- /dev/null +++ b/src/app/ui/pages/home.layout.stories.tsx @@ -0,0 +1,51 @@ +import type { Meta } from '@storybook/react'; +import { Box, Flex, Stack } from 'leather-styles/jsx'; + +import { RouteUrls } from '@shared/route-urls'; + +import { ActionButton } from '@app/ui/components/account/action-button'; +import { Tabs } from '@app/ui/components/tabs/tabs'; +import { ArrowDownIcon, ArrowUpIcon, PlusIcon, SwapIcon } from '@app/ui/icons'; + +import { HomeLayout as Component } from './home.layout'; + +const meta: Meta = { + component: Component, + tags: ['autodocs'], + title: 'Design System/Pages/Home', +}; + +export default meta; + +export function HomeLayout() { + return ( + + } label="Send" /> + } label="Receive" /> + } label="Buy" /> + } label="Swap" /> + + } + > + + + + + Assets + + + Activity + + + + + + + ); +} diff --git a/src/app/ui/pages/home.layout.tsx b/src/app/ui/pages/home.layout.tsx new file mode 100644 index 00000000000..f0b65be2f17 --- /dev/null +++ b/src/app/ui/pages/home.layout.tsx @@ -0,0 +1,31 @@ +import type { ReactNode } from 'react'; + +import { HomePageSelectors } from '@tests/selectors/home.selectors'; +import { Box, Stack } from 'leather-styles/jsx'; + +interface HomeLayoutProps { + children: ReactNode; + accountCard: ReactNode; +} + +export function HomeLayout({ children, accountCard }: HomeLayoutProps) { + return ( + + + {accountCard} + + {children} + + ); +} diff --git a/src/app/ui/pages/two-column.layout.stories.tsx b/src/app/ui/pages/two-column.layout.stories.tsx new file mode 100644 index 00000000000..482571827d5 --- /dev/null +++ b/src/app/ui/pages/two-column.layout.stories.tsx @@ -0,0 +1,20 @@ +import type { Meta } from '@storybook/react'; +import { Box } from 'leather-styles/jsx'; + +import { TwoColumnLayout as Component } from './two-column.layout'; + +const meta: Meta = { + component: Component, + tags: ['autodocs'], + title: 'Design System/Layout/TwoColumnLayout', +}; + +export default meta; + +export function TwoColumnLayout() { + return ( + Hello world} content={

    lorem ipsum

    } action={<>some action}> + +
    + ); +} diff --git a/src/app/ui/pages/two-column.layout.tsx b/src/app/ui/pages/two-column.layout.tsx new file mode 100644 index 00000000000..2dfe8676b29 --- /dev/null +++ b/src/app/ui/pages/two-column.layout.tsx @@ -0,0 +1,60 @@ +import { Box, Flex, Stack, styled } from 'leather-styles/jsx'; + +interface TwoColumnLayoutProps { + title: React.JSX.Element; + content: React.JSX.Element; + action?: React.JSX.Element; + children: React.JSX.Element; + wideChild?: boolean; +} + +export function TwoColumnLayout({ + title, + content, + action, + children, + wideChild, +}: TwoColumnLayoutProps): React.JSX.Element { + return ( + + + + {title} + {content} + {action} + + + + + + {children} + + + + ); +} diff --git a/src/app/ui/pages/welcome.layout.tsx b/src/app/ui/pages/welcome.layout.tsx new file mode 100644 index 00000000000..6a2679569f0 --- /dev/null +++ b/src/app/ui/pages/welcome.layout.tsx @@ -0,0 +1,143 @@ +import { OnboardingSelectors } from '@tests/selectors/onboarding.selectors'; +import { Flex, styled } from 'leather-styles/jsx'; + +import { useThemeSwitcher } from '@app/common/theme-provider'; +import { Button } from '@app/ui/components/button/button'; +import { Link } from '@app/ui/components/link/link'; +import { LettermarkIcon } from '@app/ui/icons/lettermark-icon'; +import { LogomarkIcon } from '@app/ui/icons/logomark-icon'; + +interface WelcomeLayoutProps { + isGeneratingWallet: boolean; + onSelectConnectLedger(): void; + onStartOnboarding(): void; + onRestoreWallet(): void; +} +export function WelcomeLayout({ + isGeneratingWallet, + onStartOnboarding, + onSelectConnectLedger, + onRestoreWallet, +}: WelcomeLayoutProps): React.JSX.Element { + // On this page 'theme' is used to set specific colours and bypass automatic theming + const { theme } = useThemeSwitcher(); + // hardcoded specific instances of colour variables needed to bypass theme + const inkBgSecondary = '#F5F1ED'; + const inkTextPrimary = '#12100F'; + + const primaryActionButton = { + p: 'space.03', + minWidth: '148px', + bg: { + base: inkBgSecondary, + md: theme === 'light' ? inkBgSecondary : inkTextPrimary, + }, + color: { + base: inkTextPrimary, + md: theme === 'light' ? inkTextPrimary : inkBgSecondary, + }, + + _hover: { + bg: 'ink.action-primary-hover', + color: theme === 'light' ? inkBgSecondary : inkTextPrimary, + }, + }; + const secondaryActionButton = { + p: 'space.03', + minWidth: '148px', + color: { base: inkBgSecondary, md: theme === 'light' ? inkBgSecondary : inkTextPrimary }, + border: `1px solid ${inkBgSecondary}`, + borderColor: { base: inkBgSecondary, md: theme === 'light' ? inkBgSecondary : inkTextPrimary }, + _hover: { + bg: 'ink.action-primary-hover', + color: 'ink.background-secondary', + }, + }; + + const tagline = 'Bitcoin for the rest of us'; + const taglineExtended = 'The bitcoin wallet for the rest of us'; + const subheader = + 'Leather is the only Bitcoin wallet you need to tap into the emerging Bitcoin economy'; + + return ( + + + + + {tagline} + + + {taglineExtended} + + + + {subheader} + + + + + + + + + + + + + + + + leather.io + + + + + + + ); +} diff --git a/src/app/ui/utils/prism.tsx b/src/app/ui/utils/prism.tsx index e4ae2112869..3a69ba152da 100644 --- a/src/app/ui/utils/prism.tsx +++ b/src/app/ui/utils/prism.tsx @@ -90,7 +90,7 @@ export type Language = export const theme: PrismTheme = { plain: { color: '#fff', - backgroundColor: 'transparent', + background: 'transparent', }, styles: [ { diff --git a/src/background/messaging/messaging-utils.ts b/src/background/messaging/messaging-utils.ts index c4dfac7bad3..e9422d73f56 100644 --- a/src/background/messaging/messaging-utils.ts +++ b/src/background/messaging/messaging-utils.ts @@ -2,7 +2,7 @@ import { InternalMethods } from '@shared/message-types'; import { sendMessage } from '@shared/messages'; import { RouteUrls } from '@shared/route-urls'; -import { popupCenter } from '@background/popup-center'; +import { popup } from '@background/popup'; export function getTabIdFromPort(port: chrome.runtime.Port) { return port.sender?.tab?.id ?? 0; @@ -67,5 +67,5 @@ const IS_TEST_ENV = process.env.TEST_ENV === 'true'; export async function triggerRequestWindowOpen(path: RouteUrls, urlParams: URLSearchParams) { if (IS_TEST_ENV) return openRequestInFullPage(path, urlParams); - return popupCenter({ url: `/popup-center.html#${path}?${urlParams.toString()}` }); + return popup({ url: `/popup.html#${path}?${urlParams.toString()}` }); } diff --git a/src/background/popup-center.ts b/src/background/popup-center.ts deleted file mode 100644 index 5720a460c6f..00000000000 --- a/src/background/popup-center.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { POPUP_CENTER_HEIGHT, POPUP_CENTER_WIDTH } from '@shared/constants'; - -interface PopupOptions { - url?: string; - title?: string; - w?: number; - h?: number; - skipPopupFallback?: boolean; -} -export function popupCenter(options: PopupOptions): Promise { - const { url, w = POPUP_CENTER_WIDTH, h = POPUP_CENTER_HEIGHT } = options; - - return new Promise(resolve => { - // @see https://developer.chrome.com/docs/extensions/reference/windows/#method-getCurrent - chrome.windows.getCurrent(async win => { - // these units take into account the distance from - // the farthest left/top sides of all displays - const dualScreenLeft = win.left ?? 0; - const dualScreenTop = win.top ?? 0; - - // dimensions of the window that originated the action - const width = win.width ?? 0; - const height = win.height ?? 0; - - const left = Math.floor(width / 2 - w / 2 + dualScreenLeft); - const top = Math.floor(height / 2 - h / 2 + dualScreenTop); - - const popup = await chrome.windows.create({ - url, - width: w, - height: h, - top, - left, - focused: true, - type: 'popup', - }); - - resolve(popup); - }); - }); -} diff --git a/src/background/popup.ts b/src/background/popup.ts new file mode 100644 index 00000000000..4ab68d7331f --- /dev/null +++ b/src/background/popup.ts @@ -0,0 +1,63 @@ +import { pxStringToNumber } from '@shared/utils/px-string-to-number'; + +// FIXME import from '@leather-wallet/tokens' +// import { tokens } from '../../theme/tokens'; +/** + * importing from tokens gives TS error about + * + * You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders +| value: { fontFamily: firaCode, fontSize: '0.6rem', lineHeight: '1rem' }, +| }, +> } as const; + */ + +const tokens = { + sizes: { + popupWidth: { value: '390px' }, + popupHeight: { value: '756px' }, + }, +}; + +interface PopupOptions { + url?: string; + title?: string; + skipPopupFallback?: boolean; +} + +export function popup(options: PopupOptions): Promise { + // TODO 4370 - ask about this + // if APP already open in full screen the window opens in a full screen and looks weird + const { url } = options; + + const popupWidth = pxStringToNumber(tokens.sizes.popupWidth.value); + const popupHeight = pxStringToNumber(tokens.sizes.popupHeight.value); + + return new Promise(resolve => { + // @see https://developer.chrome.com/docs/extensions/reference/windows/#method-getCurrent + chrome.windows.getCurrent(async win => { + // these units take into account the distance from + // the farthest left/top sides of all displays + const dualScreenLeft = win.left ?? 0; + const dualScreenTop = win.top ?? 0; + + // dimensions of the window that originated the action + const width = win.width ?? 0; + const height = win.height ?? 0; + + const left = Math.floor(width / 2 - popupWidth / 2 + dualScreenLeft); + const top = Math.floor(height / 2 - popupHeight / 2 + dualScreenTop); + + const popup = await chrome.windows.create({ + url, + width: popupWidth, + height: popupHeight, + top, + left, + focused: true, + type: 'popup', + }); + + resolve(popup); + }); + }); +} diff --git a/src/shared/constants.ts b/src/shared/constants.ts index f3138a0868c..b68372997a6 100644 --- a/src/shared/constants.ts +++ b/src/shared/constants.ts @@ -4,9 +4,6 @@ import { Blockchains } from './models/blockchain.model'; export const gaiaUrl = 'https://hub.blockstack.org'; -export const POPUP_CENTER_WIDTH = 442; -export const POPUP_CENTER_HEIGHT = 646; - export const HIGH_FEE_AMOUNT_STX = 5; export const HIGH_FEE_WARNING_LEARN_MORE_URL_BTC = 'https://bitcoinfees.earn.com/'; export const HIGH_FEE_WARNING_LEARN_MORE_URL_STX = 'https://hiro.so/questions/fee-estimates'; diff --git a/src/shared/route-urls.ts b/src/shared/route-urls.ts index 2ca8451ca83..e58fa2852eb 100644 --- a/src/shared/route-urls.ts +++ b/src/shared/route-urls.ts @@ -52,9 +52,9 @@ export enum RouteUrls { BitcoinContractList = '/bitcoin-contract-list', // Modal routes - ChangeTheme = 'change-theme', + // ChangeTheme = 'change-theme', EditNonce = 'edit-nonce', - SelectNetwork = 'choose-network', + // SelectNetwork = 'choose-network', SignOutConfirm = 'sign-out', RetrieveTaprootFunds = 'retrieve-taproot-funds', @@ -65,6 +65,7 @@ export enum RouteUrls { SendCryptoAssetFormRecipientAccounts = 'recipient-accounts', SendCryptoAssetFormRecipientBns = 'recipient-bns', SendBtcChooseFee = '/send/btc/choose-fee', + SendBtcError = '/send/btc/error', SendBtcConfirmation = '/send/btc/confirm', SendBtcDisabled = '/send/btc/disabled', SendStxConfirmation = '/send/stx/confirm', diff --git a/src/shared/utils/px-string-to-number.spec.ts b/src/shared/utils/px-string-to-number.spec.ts new file mode 100644 index 00000000000..738f80f0276 --- /dev/null +++ b/src/shared/utils/px-string-to-number.spec.ts @@ -0,0 +1,12 @@ +import { pxStringToNumber } from './px-string-to-number'; + +describe('convert px string to number for calculation', () => { + it('converts standard px string to number', () => { + const result = pxStringToNumber('10px'); + expect(result).toEqual(10); + }); + it('converts token px string to number', () => { + const result = pxStringToNumber('600px'); + expect(result).toEqual(600); + }); +}); diff --git a/src/shared/utils/px-string-to-number.ts b/src/shared/utils/px-string-to-number.ts new file mode 100644 index 00000000000..f942018d314 --- /dev/null +++ b/src/shared/utils/px-string-to-number.ts @@ -0,0 +1,3 @@ +export function pxStringToNumber(pxString: string): number { + return +pxString.replace('px', ''); +} diff --git a/test-app/src/components/app.tsx b/test-app/src/components/app.tsx index 6fc725e1f05..fa913eb5d87 100755 --- a/test-app/src/components/app.tsx +++ b/test-app/src/components/app.tsx @@ -2,9 +2,9 @@ import React from 'react'; import { AppContext } from '@common/context'; import { useAuth } from '@common/use-auth'; -import { Header } from '@components/header'; import { Home } from '@components/home'; import { Connect } from '@stacks/connect-react'; +import { Box, styled } from 'leather-styles/jsx'; import { Flex } from 'leather-styles/jsx'; export const App: React.FC = () => { @@ -17,7 +17,22 @@ export const App: React.FC = () => { {/*These are for tests*/} {authResponse && } {appPrivateKey && } -
    + + {state.userData ? ( + + { + handleSignOut(); + }} + > + Sign out + + + ) : null} + diff --git a/test-app/src/components/bns.tsx b/test-app/src/components/bns.tsx index 50e30a3065d..21c0c754974 100644 --- a/test-app/src/components/bns.tsx +++ b/test-app/src/components/bns.tsx @@ -2,6 +2,8 @@ import React from 'react'; import { Box, styled } from 'leather-styles/jsx'; +/** TODO 4370 - Delete this as the link is broken ???? */ +/** @deprecated */ export const Bns = () => { return ( diff --git a/test-app/src/components/counter-actions.tsx b/test-app/src/components/counter-actions.tsx index 50590867e84..94a34fba30e 100644 --- a/test-app/src/components/counter-actions.tsx +++ b/test-app/src/components/counter-actions.tsx @@ -5,7 +5,7 @@ import { AppContext } from '@common/context'; import { getRPCClient, stacksTestnetNetwork as network } from '@common/utils'; import { ExplorerLink } from '@components/explorer-link'; import { useConnect } from '@stacks/connect-react'; -import { Box, styled } from 'leather-styles/jsx'; +import { Box, Flex, styled } from 'leather-styles/jsx'; export const CounterActions: React.FC = () => { const { userData } = React.useContext(AppContext); @@ -54,26 +54,30 @@ export const CounterActions: React.FC = () => { return ( - {!userData && Log in to change the state of this smart contract.} - - - - - + + {error && ( - + {error} - + )} {txId && !loading && } {counter !== null && !loading && ( - Current counter value: {counter} + Current counter value: {counter} )} ); diff --git a/test-app/src/components/header.tsx b/test-app/src/components/header.tsx deleted file mode 100644 index d98839c4e4f..00000000000 --- a/test-app/src/components/header.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React, { useContext } from 'react'; - -import { AppContext } from '@common/context'; -import { Link } from '@components/link'; -import { Box, styled } from 'leather-styles/jsx'; - -interface HeaderProps { - signOut: () => void; -} - -export const Header: React.FC = ({ signOut }) => { - const state = useContext(AppContext); - return ( - - {state.userData ? ( - - { - signOut(); - }} - > - Sign out - - - ) : null} - - ); -}; diff --git a/tests/page-object-models/home.page.ts b/tests/page-object-models/home.page.ts index e54b5b11b18..759d07ff0ab 100644 --- a/tests/page-object-models/home.page.ts +++ b/tests/page-object-models/home.page.ts @@ -35,7 +35,7 @@ export class HomePage { constructor(page: Page) { this.page = page; - this.drawerActionButton = page.getByTestId(HomePageSelectors.DrawerHeaderActionBtn); + this.drawerActionButton = page.getByTestId(HomePageSelectors.HeaderActionBtn); this.receiveButton = page.getByTestId(HomePageSelectors.ReceiveCryptoAssetBtn); this.sendButton = page.getByTestId(HomePageSelectors.SendCryptoAssetBtn); this.swapButton = page.getByTestId(HomePageSelectors.SwapBtn); @@ -55,7 +55,7 @@ export class HomePage { this.fundAccountBtn = page.getByTestId(HomePageSelectors.FundAccountBtn); } - async goToReceiveModal() { + async goToReceiveDialog() { await this.page.getByTestId(HomePageSelectors.ReceiveCryptoAssetBtn).click(); } @@ -69,7 +69,7 @@ export class HomePage { // https://github.com/microsoft/playwright/issues/12168 // Using the `Receive` route to get the account address for now. async getReceiveNativeSegwitAddress() { - await this.goToReceiveModal(); + await this.goToReceiveDialog(); await this.page.getByTestId(HomePageSelectors.ReceiveBtcNativeSegwitQrCodeBtn).click(); const displayerAddress = await this.page .getByTestId(SharedComponentsSelectors.AddressDisplayer) @@ -79,14 +79,20 @@ export class HomePage { // Currently under Ordinals receive flow async getReceiveTaprootAddress() { - await this.goToReceiveModal(); + await this.goToReceiveDialog(); + await this.page.getByTestId(HomePageSelectors.ReceiveCollectiblesTab).click(); await this.page.getByTestId(HomePageSelectors.ReceiveBtcTaprootQrCodeBtn).click(); - await this.page.getByRole('button', { name: 'Copy address' }).click(); - return this.page.evaluate('navigator.clipboard.readText()'); + // await this.page.getByRole('button', { name: 'Copy address' }).click(); + // const address = await this.page.evaluate('navigator.clipboard.readText()'); + // return address; + const displayerAddress = await this.page + .getByTestId(SharedComponentsSelectors.AddressDisplayer) + .innerText(); + return displayerAddress.replaceAll('\n', ''); } async getReceiveStxAddress() { - await this.goToReceiveModal(); + await this.goToReceiveDialog(); // In Ledger mode, this element isn't visible, so clicking is conditional const qrCodeBtn = this.page.getByTestId(HomePageSelectors.ReceiveStxQrCodeBtn); if (await qrCodeBtn.isVisible()) await qrCodeBtn.click(); diff --git a/tests/page-object-models/onboarding.page.ts b/tests/page-object-models/onboarding.page.ts index a7260550a61..1c54efe4791 100644 --- a/tests/page-object-models/onboarding.page.ts +++ b/tests/page-object-models/onboarding.page.ts @@ -41,7 +41,6 @@ export const testSoftwareAccountDefaultWalletState = { userSelectedTheme: 'system', hasAllowedAnalytics: false, dismissedMessages: [], - hasApprovedNewBrand: true, }, _persist: { version: 2, rehydrated: true }, }; diff --git a/tests/page-object-models/send.page.ts b/tests/page-object-models/send.page.ts index edb0b419c57..9ca91269d74 100644 --- a/tests/page-object-models/send.page.ts +++ b/tests/page-object-models/send.page.ts @@ -94,7 +94,7 @@ export class SendPage { } async goBack() { - await this.page.getByTestId(SharedComponentsSelectors.ModalHeaderBackBtn).click(); + await this.page.getByTestId(SharedComponentsSelectors.HeaderBackBtn).click(); } async goBackSelectStx() { diff --git a/tests/selectors/home.selectors.ts b/tests/selectors/home.selectors.ts index 0b64be33b76..3ef13cea3f3 100644 --- a/tests/selectors/home.selectors.ts +++ b/tests/selectors/home.selectors.ts @@ -1,8 +1,10 @@ export enum HomePageSelectors { - DrawerHeaderActionBtn = 'drawer-header-action-btn', + HeaderActionBtn = 'header-action-btn', HomePageContainer = 'home-page-container', ReceiveCryptoAssetBtn = 'receive-crypto-asset-btn', ReceiveBtcNativeSegwitQrCodeBtn = 'receive-native-segwit-qr-code-btn', + ReceiveAssetsTab = 'receive-assets-tab', + ReceiveCollectiblesTab = 'receive-collectibles-tab', ReceiveBtcTaprootQrCodeBtn = 'receive-taproot-qr-code-btn', ReceiveStxQrCodeBtn = 'receive-stx-qr-code-btn', SendCryptoAssetBtn = 'send-crypto-asset-btn', diff --git a/tests/selectors/onboarding.selectors.ts b/tests/selectors/onboarding.selectors.ts index 9371afc424a..fa4e8cb66f7 100644 --- a/tests/selectors/onboarding.selectors.ts +++ b/tests/selectors/onboarding.selectors.ts @@ -2,7 +2,7 @@ export enum OnboardingSelectors { AllowAnalyticsBtn = 'allow-analytics-btn', BackUpSecretKeyBtn = 'back-up-secret-key-btn', DenyAnalyticsBtn = 'deny-analytics-btn', - LeatherLogoRouteToHome = 'leather-logo-route-to-home', + LogoRouteToHome = 'logo-route-to-home', NewPasswordInput = 'set-or-enter-password-input', NoAssetsFundAccountLink = 'no-assets-fund-account-link', SecretKey = 'secret-key', diff --git a/tests/selectors/settings.selectors.ts b/tests/selectors/settings.selectors.ts index 25d88c0d572..3190412d91e 100644 --- a/tests/selectors/settings.selectors.ts +++ b/tests/selectors/settings.selectors.ts @@ -20,7 +20,8 @@ export enum SettingsSelectors { BtnAddNetwork = 'btn-add-network', ShowSecretKeyBtn = 'show-secret-key-btn', GetSupportMenuItem = 'get-support-menu-item', - SettingsMenuBtn = 'settings-menu-btn', + SettingsMenuBtn = 'settings-menu--trigger', + SwitchAccountTrigger = 'switch-account-trigger', SwitchAccountMenuItem = 'switch-account-menu-item', SwitchAccountItemIndex = 'switch-account-item-[index]', OpenWalletInNewTab = 'open-wallet-in-new-tab', diff --git a/tests/selectors/shared-component.selectors.ts b/tests/selectors/shared-component.selectors.ts index 1090a4c75f1..a35d548cf25 100644 --- a/tests/selectors/shared-component.selectors.ts +++ b/tests/selectors/shared-component.selectors.ts @@ -19,9 +19,7 @@ export enum SharedComponentsSelectors { FeesListItem = 'fee-list-item', FeesListItemFeeValue = 'fee-list-item-fee-value', - // Modal Header - ModalHeaderBackBtn = 'modal-header-back-button', - // Error BroadcastErrorTitle = 'broadcast-error-title', + HeaderBackBtn = 'header-back-button', } diff --git a/tests/specs/settings/settings-menu.spec.ts b/tests/specs/settings/settings.spec.ts similarity index 97% rename from tests/specs/settings/settings-menu.spec.ts rename to tests/specs/settings/settings.spec.ts index 48c7bb71d37..92a825fa117 100644 --- a/tests/specs/settings/settings-menu.spec.ts +++ b/tests/specs/settings/settings.spec.ts @@ -4,6 +4,7 @@ import { SettingsSelectors } from '@tests/selectors/settings.selectors'; import { test } from '../../fixtures/fixtures'; +// FIXME PETE - this test needs to be updated and improved test.describe('Settings menu', () => { test.beforeEach(async ({ extensionId, globalPage, onboardingPage }) => { await globalPage.setupAndUseApiCalls(extensionId); diff --git a/theme/global/full-page-styles.ts b/theme/global/full-page-styles.ts deleted file mode 100644 index e4a41367579..00000000000 --- a/theme/global/full-page-styles.ts +++ /dev/null @@ -1,14 +0,0 @@ -export const fullPageStyles = { - '.mode__full-page': { - '&, body, main, .radix-themes': { - height: '100%', - maxHeight: 'unset', - width: '100%', - }, - '.main-content': { - flexGrow: 1, - justifyContent: 'center', - margin: '0 auto', - }, - }, -}; diff --git a/theme/global/global.ts b/theme/global/global.ts index fdec95e9a18..fca0794f3cc 100644 --- a/theme/global/global.ts +++ b/theme/global/global.ts @@ -1,20 +1,24 @@ import { defineGlobalStyles } from '@pandacss/dev'; -import { fullPageStyles } from './full-page-styles'; -import { popupCenterStyles } from './popup-center-styles'; -import { popupStyles } from './popup-styles'; +// TODO import from '@leather-wallet/tokens' +import { tokens } from '../tokens'; + +// 4370 TODO audit the use of this file as we are pretty close to not needing it +// - could set some styles in the