From aa3ca896167c36976382f1ec3dbb55b8df2fe578 Mon Sep 17 00:00:00 2001 From: Hayden Briese Date: Fri, 23 Aug 2024 14:27:42 +1000 Subject: [PATCH] feat(app): implement Snackbar with react-call --- ...essage-npm-2.2.0-c76c7088d0-5d4e18eb6b.zip | Bin 30175 -> 0 bytes app/package.json | 1 - app/src/app/(nav)/[account]/swap.tsx | 2 +- app/src/app/(sheet)/link.tsx | 2 +- app/src/app/(sheet)/select/address.tsx | 2 +- app/src/app/(sheet)/sessions/connect/[id].tsx | 4 +- app/src/app/(sheet)/wc.tsx | 2 +- app/src/app/_layout.tsx | 4 +- app/src/app/auth.tsx | 2 +- app/src/app/scan.tsx | 2 +- app/src/components/ScanOverlay.tsx | 2 +- app/src/components/Snackbar.tsx | 115 +++++++++++++++ .../components/account/PolicySuggestions.tsx | 1 - app/src/components/auth/PasswordSettings.tsx | 2 +- .../components/cloud/google/useLinkGoogle.ts | 2 +- app/src/components/cloud/useLinkApple.ts | 2 +- app/src/components/link/ledger/LedgerItem.tsx | 11 +- .../components/policy/ApprovalSettings.tsx | 21 ++- app/src/components/policy/PolicySideSheet.tsx | 4 +- .../components/provider/SnackbarProvider.tsx | 135 ------------------ .../components/provider/UpdateProvider.tsx | 12 +- .../transaction/ScheduleSection.tsx | 1 - .../transaction/TransactionResponse.tsx | 2 +- .../transaction/useSignWithApprover.ts | 4 +- .../useSessionConnectionListener.ts | 2 +- .../useSessionRequestListener.ts | 2 +- app/src/hooks/mutations/useRemovePolicy.ts | 2 +- app/src/hooks/useApprove.ts | 2 +- app/src/hooks/useReject.ts | 2 +- app/src/lib/share/index.ts | 2 +- yarn.lock | 11 -- 31 files changed, 160 insertions(+), 198 deletions(-) delete mode 100644 .yarn/cache/react-native-toast-message-npm-2.2.0-c76c7088d0-5d4e18eb6b.zip create mode 100644 app/src/components/Snackbar.tsx delete mode 100644 app/src/components/provider/SnackbarProvider.tsx diff --git a/.yarn/cache/react-native-toast-message-npm-2.2.0-c76c7088d0-5d4e18eb6b.zip b/.yarn/cache/react-native-toast-message-npm-2.2.0-c76c7088d0-5d4e18eb6b.zip deleted file mode 100644 index 67b2eb04831e92f54d6b31f7bf948f480d82584e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30175 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 - + diff --git a/app/src/app/auth.tsx b/app/src/app/auth.tsx index ff3b6cfa4..32cec284d 100644 --- a/app/src/app/auth.tsx +++ b/app/src/app/auth.tsx @@ -20,7 +20,7 @@ import { useEffect } from 'react'; import AsyncStorage from '@react-native-async-storage/async-storage'; import * as Updates from 'expo-updates'; import { Confirm } from '#/Confirm'; -import { showInfo } from '#/provider/SnackbarProvider'; +import { showInfo } from '#/Snackbar'; const UNLOCKED = new Subject(); const emitAuth = () => UNLOCKED.next(true); diff --git a/app/src/app/scan.tsx b/app/src/app/scan.tsx index ef8bd857b..faeb08f5a 100644 --- a/app/src/app/scan.tsx +++ b/app/src/app/scan.tsx @@ -7,7 +7,7 @@ import { Actions } from '#/layout/Actions'; import { Address, UAddress, tryAsAddress } from 'lib'; import * as Linking from 'expo-linking'; import useAsyncEffect from 'use-async-effect'; -import { showError } from '#/provider/SnackbarProvider'; +import { showError } from '#/Snackbar'; import { parseAppLink } from '~/lib/appLink'; import { useFocusEffect, useRouter } from 'expo-router'; import { ScanOverlay } from '#/ScanOverlay'; diff --git a/app/src/components/ScanOverlay.tsx b/app/src/components/ScanOverlay.tsx index c553bee54..754d99640 100644 --- a/app/src/components/ScanOverlay.tsx +++ b/app/src/components/ScanOverlay.tsx @@ -2,7 +2,7 @@ import { BackIcon, ContactsIcon, PasteIcon } from '~/util/theme/icons'; import { IconButton } from 'react-native-paper'; import { StyleSheet, View } from 'react-native'; import * as Clipboard from 'expo-clipboard'; -import { showWarning } from '#/provider/SnackbarProvider'; +import { showWarning } from '#/Snackbar'; import { useSelectAddress } from '~/hooks/useSelectAddress'; import { useRouter } from 'expo-router'; import { createStyles, useStyles } from '@theme/styles'; diff --git a/app/src/components/Snackbar.tsx b/app/src/components/Snackbar.tsx new file mode 100644 index 000000000..56a361950 --- /dev/null +++ b/app/src/components/Snackbar.tsx @@ -0,0 +1,115 @@ +import { createStyles, useStyles } from '@theme/styles'; +import { useEffect } from 'react'; +import { createCallable } from 'react-call'; +import { Snackbar as BaseSnackbar, Text } from 'react-native-paper'; +import { Subject } from 'rxjs'; +import { hapticFeedback } from '~/lib/haptic'; +import { logEvent, LogEventParams } from '~/util/analytics'; + +const HIDE_SNACKBAR = new Subject(); + +type SnackbarVariant = 'info' | 'success' | 'warning' | 'error'; + +export interface SnackbarProps { + variant?: SnackbarVariant; + message: string; + duration?: number; + action?: string; + event?: Partial | boolean; +} + +export const Snackbar = createCallable( + ({ call, variant = 'info', message, duration = 6000, action, event }) => { + const { styles } = useStyles(getStylesheet({ variant })); + + useEffect(() => { + const sub = HIDE_SNACKBAR.subscribe(() => call.end(false)); + return () => sub.unsubscribe(); + }, [call]); + + useEffect(() => { + if (variant !== 'info') hapticFeedback(variant); + }, [variant]); + + useEffect(() => { + if (event && variant !== 'success') { + logEvent({ + level: variant, + message, + snackbar: true, + ...(typeof event === 'object' && event), + }); + } + }, [message, variant, event]); + + return ( + call.end(false)} + style={[styles.snackbarBase, styles.snackbar]} + {...(action && { + action: { + label: action, + labelStyle: styles.actionLabel, + onPress: () => call.end(true), + }, + })} + > + + {message} + + + ); + }, +); + +const getStylesheet = ({ variant }: { variant: SnackbarVariant }) => + createStyles(({ colors }) => { + const s = { + info: { + snackbar: { backgroundColor: colors.inverseSurface }, + message: { color: colors.inverseOnSurface }, + actionLabel: { color: colors.inversePrimary }, + }, + success: { + snackbar: { backgroundColor: colors.successContainer }, + message: { color: colors.onSuccessContainer }, + }, + warning: { + snackbar: { backgroundColor: colors.warningContainer }, + message: { color: colors.onWarningContainer }, + }, + error: { + snackbar: { backgroundColor: colors.errorContainer }, + message: { color: colors.onErrorContainer }, + }, + }[variant]; + + return { + actionLabel: { + color: colors.primary, + }, + snackbarBase: { + maxWidth: 600, + }, + ...s, + }; + }); + +type ShowOptions = Omit; + +export const showInfo = (message: string, options?: ShowOptions) => + Snackbar.call({ variant: 'info', message, ...options }); + +export const showSuccess = (message: string, options?: ShowOptions) => + Snackbar.call({ variant: 'success', message, ...options }); + +export const showWarning = (message: string, options?: ShowOptions) => + Snackbar.call({ variant: 'warning', message, ...options }); + +export const showError = (message: string, options?: ShowOptions) => + Snackbar.call({ variant: 'error', message, ...options }); + +export const hideSnackbar = () => HIDE_SNACKBAR.next(true); diff --git a/app/src/components/account/PolicySuggestions.tsx b/app/src/components/account/PolicySuggestions.tsx index f7381b177..8d277aa98 100644 --- a/app/src/components/account/PolicySuggestions.tsx +++ b/app/src/components/account/PolicySuggestions.tsx @@ -1,5 +1,4 @@ import { Chip } from '#/Chip'; -import { showError } from '#/provider/SnackbarProvider'; import { createStyles, useStyles } from '@theme/styles'; import { useRouter } from 'expo-router'; import { asChain } from 'lib'; diff --git a/app/src/components/auth/PasswordSettings.tsx b/app/src/components/auth/PasswordSettings.tsx index 5409be26b..6decd982d 100644 --- a/app/src/components/auth/PasswordSettings.tsx +++ b/app/src/components/auth/PasswordSettings.tsx @@ -11,7 +11,7 @@ import { changeSecureStorePassword } from '~/lib/secure-storage'; import { createStyles, useStyles } from '@theme/styles'; import { Actions } from '#/layout/Actions'; import { Button } from '#/Button'; -import { showInfo } from '#/provider/SnackbarProvider'; +import { showInfo } from '#/Snackbar'; const PASSWORD_HASH = persistedAtom('passwordHash', null); export const usePasswordHash = () => useAtomValue(PASSWORD_HASH); diff --git a/app/src/components/cloud/google/useLinkGoogle.ts b/app/src/components/cloud/google/useLinkGoogle.ts index 9b2837205..690768263 100644 --- a/app/src/components/cloud/google/useLinkGoogle.ts +++ b/app/src/components/cloud/google/useLinkGoogle.ts @@ -1,4 +1,4 @@ -import { showError } from '#/provider/SnackbarProvider'; +import { showError } from '#/Snackbar'; import { ampli } from '~/lib/ampli'; import { useGetGoogleApprover } from '#/cloud/google/useGetGoogleApprover'; import { graphql } from 'relay-runtime'; diff --git a/app/src/components/cloud/useLinkApple.ts b/app/src/components/cloud/useLinkApple.ts index b38a74dc3..75ad7658c 100644 --- a/app/src/components/cloud/useLinkApple.ts +++ b/app/src/components/cloud/useLinkApple.ts @@ -1,5 +1,5 @@ import { useGetAppleApprover } from './useGetAppleApprover'; -import { showError } from '#/provider/SnackbarProvider'; +import { showError } from '#/Snackbar'; import { ampli } from '~/lib/ampli'; import { graphql } from 'relay-runtime'; import { useFragment } from 'react-relay'; diff --git a/app/src/components/link/ledger/LedgerItem.tsx b/app/src/components/link/ledger/LedgerItem.tsx index 940960106..c146de947 100644 --- a/app/src/components/link/ledger/LedgerItem.tsx +++ b/app/src/components/link/ledger/LedgerItem.tsx @@ -3,7 +3,7 @@ import { useCallback } from 'react'; import { ListItem } from '#/list/ListItem'; import { useGetLedgerApprover } from '~/app/(sheet)/ledger/approve'; import { APPROVER_BLE_IDS } from '~/hooks/ledger/useLedger'; -import { showError } from '#/provider/SnackbarProvider'; +import { showError } from '#/Snackbar'; import { useImmerAtom } from 'jotai-immer'; import { getLedgerDeviceModel } from '~/hooks/ledger/connectLedger'; import { elipseTruncate } from '~/util/format'; @@ -94,10 +94,11 @@ export function LedgerItem({ device: d, ...props }: LedgerItemProps) { }, }), ); - if (!authHeaders) - return showError('Connection request cancelled', { - action: { label: 'Try again', onPress: connect }, - }); + if (!authHeaders) { + const retry = await showError('Connection request cancelled', { action: 'Try again' }); + if (retry) connect(); + return; + } // 1. Link const { approvers } = (await link({ token: user.linkingToken }, { headers: authHeaders })).link; diff --git a/app/src/components/policy/ApprovalSettings.tsx b/app/src/components/policy/ApprovalSettings.tsx index 6c7db6c99..bf7e7d660 100644 --- a/app/src/components/policy/ApprovalSettings.tsx +++ b/app/src/components/policy/ApprovalSettings.tsx @@ -9,7 +9,7 @@ import { ListItemHorizontalTrailing } from '#/list/ListItemHorizontalTrailing'; import { ListItemTrailingText } from '#/list/ListItemTrailingText'; import { ApproverItem } from '#/policy/ApproverItem'; import { ThresholdChip } from './ThresholdChip'; -import { showInfo } from '#/provider/SnackbarProvider'; +import { showInfo } from '#/Snackbar'; import { useSelectAddress } from '~/hooks/useSelectAddress'; import { useToggle } from '~/hooks/useToggle'; import { usePolicyDraft } from '~/lib/policy/policyAsDraft'; @@ -38,7 +38,7 @@ export function ApprovalSettings() { } }; - const remove = (approver: Address) => { + const remove = async (approver: Address) => { const originalThreshold = policy.threshold; update((draft) => { @@ -46,16 +46,13 @@ export function ApprovalSettings() { draft.threshold = Math.max(policy.threshold, policy.approvers.size); }); - showInfo('Approver removed', { - action: { - label: 'Undo', - onPress: () => - update((draft) => { - draft.approvers.add(approver); - draft.threshold = originalThreshold; - }), - }, - }); + const undo = await showInfo('Approver removed', { action: 'Undo' }); + if (undo) { + update((draft) => { + draft.approvers.add(approver); + draft.threshold = originalThreshold; + }); + } }; return ( diff --git a/app/src/components/policy/PolicySideSheet.tsx b/app/src/components/policy/PolicySideSheet.tsx index 81aeb9658..d3afe32b9 100644 --- a/app/src/components/policy/PolicySideSheet.tsx +++ b/app/src/components/policy/PolicySideSheet.tsx @@ -3,7 +3,7 @@ import { FormTextField } from '#/fields/FormTextField'; import { Actions } from '#/layout/Actions'; import { FormSubmitButton } from '#/fields/FormSubmitButton'; import { usePolicyDraft } from '~/lib/policy/policyAsDraft'; -import { showError } from '#/provider/SnackbarProvider'; +import { showError } from '#/Snackbar'; import { SideSheet } from '../SideSheet/SideSheet'; import { Button } from '../Button'; import { createStyles, useStyles } from '@theme/styles'; @@ -122,7 +122,7 @@ export function PolicySideSheet(props: PolicySideSheetProps) { if (policy && draft.key !== undefined) { const r = (await rename({ account: draft.account, key: draft.key, name })) ?.updatePolicyDetails; - if (r?.__typename !== 'Policy') return showError(r?.message); + if (r?.__typename !== 'Policy') return showError(r?.message || 'Unknown error'); } updateDraft((draft) => { diff --git a/app/src/components/provider/SnackbarProvider.tsx b/app/src/components/provider/SnackbarProvider.tsx deleted file mode 100644 index 2e45700ce..000000000 --- a/app/src/components/provider/SnackbarProvider.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import { createStyles, useStyles } from '@theme/styles'; -import { useEffect } from 'react'; -import { StyleProp, TextStyle } from 'react-native'; -import { Snackbar, SnackbarProps, Text } from 'react-native-paper'; -import RnToast, { ToastConfig, ToastConfigParams, ToastOptions } from 'react-native-toast-message'; -import { hapticFeedback } from '~/lib/haptic'; -import { LogEventParams, logEvent } from '~/util/analytics'; - -type SnackVariant = 'info' | 'success' | 'warning' | 'error'; - -type SnackParams = Pick & { - message: string; - variant?: SnackVariant; - messageStyle?: StyleProp; - event?: Partial | boolean; -}; - -export type SnackProps = ToastConfigParams; - -const Snack = ({ - isVisible, - hide, - props: { message, variant = 'info', messageStyle, event: eventProp, action, style, ...props }, -}: SnackProps) => { - const { styles, theme } = useStyles(getStylesheet({ variant })); - - useEffect(() => { - if (variant !== 'info') hapticFeedback(variant); - }, [variant]); - - useEffect(() => { - if (eventProp && (variant === 'warning' || variant === 'error')) { - logEvent({ - level: variant, - message, - snack: true, - ...(typeof eventProp === 'object' && eventProp), - }); - } - }, [message, variant, eventProp]); - - return ( - - {message} - - ); -}; - -const getStylesheet = ({ variant }: { variant: SnackVariant }) => - createStyles(({ colors }) => { - const s = { - info: { - snackbar: { backgroundColor: colors.inverseSurface }, - message: { color: colors.inverseOnSurface }, - actionLabel: { color: colors.inversePrimary }, - }, - success: { - snackbar: { backgroundColor: colors.successContainer }, - message: { color: colors.onSuccessContainer }, - }, - warning: { - snackbar: { backgroundColor: colors.warningContainer }, - message: { color: colors.onWarningContainer }, - }, - error: { - snackbar: { backgroundColor: colors.errorContainer }, - message: { color: colors.onErrorContainer }, - }, - }[variant]; - - return { - actionLabel: { - color: colors.primary, - }, - snackbarBase: { - maxWidth: 600, - }, - ...s, - }; - }); - -export type ShowSnackOptions = Pick< - ToastOptions, - 'autoHide' | 'visibilityTime' | 'position' | 'onHide' -> & - Omit; - -export const showSnack = ( - message: string, - { autoHide = true, visibilityTime = 5000, position, onHide, ...props }: ShowSnackOptions = {}, -) => - RnToast.show({ - type: Snack.name, - props: { - ...props, - message, - }, - autoHide, - visibilityTime, - position, - onHide, - }); - -export const showInfo = (message: string, options?: ShowSnackOptions) => - showSnack(message, { ...options, variant: 'info' }); - -export const showSuccess = (message: string, options?: ShowSnackOptions) => - showSnack(message, { ...options, variant: 'success' }); - -export const showWarning = (message: string, options?: ShowSnackOptions) => - showSnack(message, { ...options, variant: 'warning' }); - -export const showError = (message: string | undefined, options?: ShowSnackOptions) => - showSnack(message ?? 'Something went wrong', { ...options, variant: 'error' }); - -export const hideSnackbar = RnToast.hide; - -const CONFIGS: ToastConfig = { [Snack.name]: Snack }; - -export const SnackbarProvider = () => ( - -); diff --git a/app/src/components/provider/UpdateProvider.tsx b/app/src/components/provider/UpdateProvider.tsx index 2b1fa06e6..ef0b8b072 100644 --- a/app/src/components/provider/UpdateProvider.tsx +++ b/app/src/components/provider/UpdateProvider.tsx @@ -1,9 +1,8 @@ import * as Updates from 'expo-updates'; import { useEffect } from 'react'; import { AppState, Platform } from 'react-native'; -import { showInfo } from './SnackbarProvider'; -import { showWarning } from './SnackbarProvider'; import * as Sentry from '@sentry/react-native'; +import { showInfo, showWarning } from '#/Snackbar'; const UPDATE_INTEVAL = 5 * 60_000; @@ -51,11 +50,10 @@ export function UpdateProvider() { useEffect(() => { if (isUpdatePending) { showInfo('A new improved version is available. Please reload to apply the update.', { - action: { - label: 'Reload', - onPress: Updates.reloadAsync, - }, - autoHide: false, + action: 'Reload', + duration: Infinity, + }).then((confirmed) => { + confirmed && Updates.reloadAsync(); }); } }, [isUpdatePending]); diff --git a/app/src/components/transaction/ScheduleSection.tsx b/app/src/components/transaction/ScheduleSection.tsx index e6e0e35e3..4fb09b7ed 100644 --- a/app/src/components/transaction/ScheduleSection.tsx +++ b/app/src/components/transaction/ScheduleSection.tsx @@ -2,7 +2,6 @@ import { Timestamp } from '#/format/Timestamp'; import { ListHeader } from '#/list/ListHeader'; import { ListItem } from '#/list/ListItem'; import { DELAY_ENTRIES } from '#/policy/DelaySettings'; -import { showError } from '#/provider/SnackbarProvider'; import { CancelIcon, materialCommunityIcon } from '@theme/icons'; import { createStyles } from '@theme/styles'; import { useRouter } from 'expo-router'; diff --git a/app/src/components/transaction/TransactionResponse.tsx b/app/src/components/transaction/TransactionResponse.tsx index c029c6423..9cd3147f3 100644 --- a/app/src/components/transaction/TransactionResponse.tsx +++ b/app/src/components/transaction/TransactionResponse.tsx @@ -7,7 +7,7 @@ import { useFragment } from 'react-relay'; import { graphql } from 'relay-runtime'; import { TransactionResponse_transaction$key } from '~/api/__generated__/TransactionResponse_transaction.graphql'; import * as Clipboard from 'expo-clipboard'; -import { showInfo } from '#/provider/SnackbarProvider'; +import { showInfo } from '#/Snackbar'; import { size, slice } from 'viem'; import { isHex } from 'lib'; import { Link } from 'expo-router'; diff --git a/app/src/components/transaction/useSignWithApprover.ts b/app/src/components/transaction/useSignWithApprover.ts index 3905740cc..17fd120b1 100644 --- a/app/src/components/transaction/useSignWithApprover.ts +++ b/app/src/components/transaction/useSignWithApprover.ts @@ -2,13 +2,13 @@ import { useApproverWallet } from '~/lib/network/useApprover'; import { ok, err } from 'neverthrow'; import { useMemo } from 'react'; import { useAuthenticate } from '~/app/auth'; -import { showError } from '#/provider/SnackbarProvider'; +import { showError } from '#/Snackbar'; import { useAuthSettings } from '#/auth/AuthSettings'; export function useSignWithApprover() { const approver = useApproverWallet(); const auth = useAuthenticate(); - const {approval: authRequired} = useAuthSettings(); + const { approval: authRequired } = useAuthSettings(); return useMemo(() => { const check = async () => { diff --git a/app/src/components/walletconnect/WalletConnectListeners/useSessionConnectionListener.ts b/app/src/components/walletconnect/WalletConnectListeners/useSessionConnectionListener.ts index 05d010112..f6820d6c8 100644 --- a/app/src/components/walletconnect/WalletConnectListeners/useSessionConnectionListener.ts +++ b/app/src/components/walletconnect/WalletConnectListeners/useSessionConnectionListener.ts @@ -1,6 +1,6 @@ import { getSdkError } from '@walletconnect/utils'; import { useEffect, useRef } from 'react'; -import { showError } from '#/provider/SnackbarProvider'; +import { showError } from '#/Snackbar'; import { useWalletConnectWithoutWatching, sessionChains } from '~/lib/wc'; import { useRouter, usePathname, Href } from 'expo-router'; import { Web3WalletTypes } from '@walletconnect/web3wallet'; diff --git a/app/src/components/walletconnect/WalletConnectListeners/useSessionRequestListener.ts b/app/src/components/walletconnect/WalletConnectListeners/useSessionRequestListener.ts index db76bf272..913e6b8d6 100644 --- a/app/src/components/walletconnect/WalletConnectListeners/useSessionRequestListener.ts +++ b/app/src/components/walletconnect/WalletConnectListeners/useSessionRequestListener.ts @@ -1,7 +1,7 @@ import { asUAddress } from 'lib'; import { CHAINS } from 'chains'; import { useEffect } from 'react'; -import { showError, showInfo } from '#/provider/SnackbarProvider'; +import { showError, showInfo } from '#/Snackbar'; import { logError } from '~/util/analytics'; import { asCaip2, diff --git a/app/src/hooks/mutations/useRemovePolicy.ts b/app/src/hooks/mutations/useRemovePolicy.ts index aa83cb413..cd374f6e7 100644 --- a/app/src/hooks/mutations/useRemovePolicy.ts +++ b/app/src/hooks/mutations/useRemovePolicy.ts @@ -1,4 +1,4 @@ -import { showError } from '#/provider/SnackbarProvider'; +import { showError } from '#/Snackbar'; import { useRouter } from 'expo-router'; import { PolicyKey, UAddress } from 'lib'; import { graphql } from 'relay-runtime'; diff --git a/app/src/hooks/useApprove.ts b/app/src/hooks/useApprove.ts index 641fbc3e6..aab740f45 100644 --- a/app/src/hooks/useApprove.ts +++ b/app/src/hooks/useApprove.ts @@ -1,7 +1,7 @@ import { useApproverAddress } from '~/lib/network/useApprover'; import { Address, asMessageTypedData, UUID } from 'lib'; import { match } from 'ts-pattern'; -import { showError } from '#/provider/SnackbarProvider'; +import { showError } from '#/Snackbar'; import { proposalAsTypedData } from '~/lib/proposalAsTypedData'; import { useGetLedgerApprover } from '~/app/(sheet)/ledger/approve'; import { useSignWithApprover } from '#/transaction/useSignWithApprover'; diff --git a/app/src/hooks/useReject.ts b/app/src/hooks/useReject.ts index b4faf2168..361785951 100644 --- a/app/src/hooks/useReject.ts +++ b/app/src/hooks/useReject.ts @@ -1,7 +1,7 @@ import { useApproverAddress } from '~/lib/network/useApprover'; import { Address } from 'lib'; import { match } from 'ts-pattern'; -import { showError } from '#/provider/SnackbarProvider'; +import { showError } from '#/Snackbar'; import { hapticFeedback } from '~/lib/haptic'; import { ampli, type RejectionProperties } from '~/lib/ampli'; import { useGetGoogleApprover } from '#/cloud/google/useGetGoogleApprover'; diff --git a/app/src/lib/share/index.ts b/app/src/lib/share/index.ts index c0573b34d..b1d5a5a5d 100644 --- a/app/src/lib/share/index.ts +++ b/app/src/lib/share/index.ts @@ -1,5 +1,5 @@ import Clipboard from '@react-native-clipboard/clipboard'; -import { showInfo } from '#/provider/SnackbarProvider'; +import { showInfo } from '#/Snackbar'; export interface ShareOptions { message?: string; diff --git a/yarn.lock b/yarn.lock index 7bd55ff10..aa29112e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14188,7 +14188,6 @@ __metadata: react-native-screens: "npm:3.31.1" react-native-svg: "npm:15.2.0" react-native-tab-view: "npm:^3.5.2" - react-native-toast-message: "npm:^2.2.0" react-native-typewriter: "npm:^0.7.0" react-native-unistyles: "npm:^2.9.1" react-native-web: "npm:~0.19.12" @@ -30731,16 +30730,6 @@ __metadata: languageName: node linkType: hard -"react-native-toast-message@npm:^2.2.0": - version: 2.2.0 - resolution: "react-native-toast-message@npm:2.2.0" - peerDependencies: - react: "*" - react-native: "*" - checksum: 10/5d4e18eb6bcdcf117c64242e09dd1fc791a51d614dcafc7ef685942dbf891010b8901cb5a6093088d65607f77b417cdc4053fb1bef7a8e119e2776063d32b78f - languageName: node - linkType: hard - "react-native-typewriter@npm:^0.7.0": version: 0.7.0 resolution: "react-native-typewriter@npm:0.7.0"