diff --git a/packages/common/src/hooks/purchaseContent/constants.ts b/packages/common/src/hooks/purchaseContent/constants.ts index 7b1eec3f6d2..be4dc23c401 100644 --- a/packages/common/src/hooks/purchaseContent/constants.ts +++ b/packages/common/src/hooks/purchaseContent/constants.ts @@ -1,6 +1,7 @@ export const CUSTOM_AMOUNT = 'customAmount' export const AMOUNT_PRESET = 'amountPreset' export const PURCHASE_METHOD = 'purchaseMethod' +export const PAGE = 'page' // Pay between $1 and $100 extra export const minimumPayExtraAmountCents = 100 diff --git a/packages/common/src/hooks/purchaseContent/types.ts b/packages/common/src/hooks/purchaseContent/types.ts index 67120100244..9ed253b36fc 100644 --- a/packages/common/src/hooks/purchaseContent/types.ts +++ b/packages/common/src/hooks/purchaseContent/types.ts @@ -25,3 +25,5 @@ export type USDCPurchaseConfig = { minUSDCPurchaseAmountCents: number maxUSDCPurchaseAmountCents: number } + +export type PurchasePage = 'purchase' | 'crypto-transfer' diff --git a/packages/common/src/hooks/purchaseContent/usePurchaseContentFormConfiguration.ts b/packages/common/src/hooks/purchaseContent/usePurchaseContentFormConfiguration.ts index 5c6a528a932..8e49d75d926 100644 --- a/packages/common/src/hooks/purchaseContent/usePurchaseContentFormConfiguration.ts +++ b/packages/common/src/hooks/purchaseContent/usePurchaseContentFormConfiguration.ts @@ -8,11 +8,11 @@ import { PurchaseMethod } from 'models/PurchaseContent' import { UserTrackMetadata } from 'models/Track' import { ContentType, + PurchaseContentPage, isContentPurchaseInProgress, purchaseContentActions, purchaseContentSelectors } from 'store/purchase-content' -import { useUSDCManualTransferModal } from 'store/ui' import { Nullable } from 'utils/typeUtils' import { useUSDCBalance } from '../useUSDCBalance' @@ -27,9 +27,12 @@ import { PayExtraAmountPresetValues, PayExtraPreset } from './types' import { getExtraAmount } from './utils' import { PurchaseContentSchema, PurchaseContentValues } from './validation' -const { startPurchaseContentFlow } = purchaseContentActions -const { getPurchaseContentFlowStage, getPurchaseContentError } = - purchaseContentSelectors +const { startPurchaseContentFlow, setPurchasePage } = purchaseContentActions +const { + getPurchaseContentFlowStage, + getPurchaseContentError, + getPurchaseContentPage +} = purchaseContentSelectors export const usePurchaseContentFormConfiguration = ({ track, @@ -41,9 +44,9 @@ export const usePurchaseContentFormConfiguration = ({ presetValues: PayExtraAmountPresetValues }) => { const dispatch = useDispatch() - const { onOpen: openUsdcManualTransferModal } = useUSDCManualTransferModal() const stage = useSelector(getPurchaseContentFlowStage) const error = useSelector(getPurchaseContentError) + const page = useSelector(getPurchaseContentPage) const isUnlocking = !error && isContentPurchaseInProgress(stage) const { data: balanceBN } = useUSDCBalance() const balance = USDC(balanceBN ?? new BN(0)).value @@ -60,36 +63,29 @@ export const usePurchaseContentFormConfiguration = ({ ({ customAmount, amountPreset, purchaseMethod }: PurchaseContentValues) => { if (isUnlocking || !track?.track_id) return - const extraAmount = getExtraAmount({ - amountPreset, - presetValues, - customAmount - }) - const startPurchaseAction = startPurchaseContentFlow({ - purchaseMethod, - extraAmount, - extraAmountPreset: amountPreset, - contentId: track.track_id, - contentType: ContentType.TRACK - }) - - if (purchaseMethod === PurchaseMethod.CRYPTO) { - openUsdcManualTransferModal({ - amount: price + extraAmount, - onSuccessAction: startPurchaseAction - }) + if ( + purchaseMethod === PurchaseMethod.CRYPTO && + page === PurchaseContentPage.PURCHASE + ) { + dispatch(setPurchasePage({ page: PurchaseContentPage.TRANSFER })) } else { - dispatch(startPurchaseAction) + const extraAmount = getExtraAmount({ + amountPreset, + presetValues, + customAmount + }) + dispatch( + startPurchaseContentFlow({ + purchaseMethod, + extraAmount, + extraAmountPreset: amountPreset, + contentId: track.track_id, + contentType: ContentType.TRACK + }) + ) } }, - [ - isUnlocking, - track, - presetValues, - dispatch, - openUsdcManualTransferModal, - price - ] + [isUnlocking, track, page, presetValues, dispatch] ) return { diff --git a/packages/common/src/store/purchase-content/selectors.ts b/packages/common/src/store/purchase-content/selectors.ts index c0cc56d7606..db690dff85d 100644 --- a/packages/common/src/store/purchase-content/selectors.ts +++ b/packages/common/src/store/purchase-content/selectors.ts @@ -6,6 +6,9 @@ export const getPurchaseContentId = (state: CommonState) => export const getPurchaseContentType = (state: CommonState) => state.purchaseContent.contentType +export const getPurchaseContentPage = (state: CommonState) => + state.purchaseContent.page + export const getPurchaseContentFlowStage = (state: CommonState) => state.purchaseContent.stage diff --git a/packages/common/src/store/purchase-content/slice.ts b/packages/common/src/store/purchase-content/slice.ts index bbe1f1268d8..3c3c4d38fca 100644 --- a/packages/common/src/store/purchase-content/slice.ts +++ b/packages/common/src/store/purchase-content/slice.ts @@ -6,6 +6,7 @@ import { PurchaseMethod } from 'models/PurchaseContent' import { ContentType, PurchaseContentError, + PurchaseContentPage, PurchaseContentStage } from './types' @@ -15,6 +16,7 @@ type OnSuccess = { } type PurchaseContentState = { + page: PurchaseContentPage stage: PurchaseContentStage contentType: ContentType contentId: ID @@ -28,6 +30,7 @@ type PurchaseContentState = { } const initialState: PurchaseContentState = { + page: PurchaseContentPage.PURCHASE, contentType: ContentType.TRACK, contentId: -1, extraAmount: undefined, @@ -52,6 +55,7 @@ const slice = createSlice({ onSuccess?: OnSuccess }> ) => { + state.page = PurchaseContentPage.PURCHASE state.stage = PurchaseContentStage.START state.error = undefined state.extraAmount = action.payload.extraAmount @@ -81,6 +85,12 @@ const slice = createSlice({ ) => { state.stage = PurchaseContentStage.FINISH }, + setPurchasePage: ( + state, + action: PayloadAction<{ page: PurchaseContentPage }> + ) => { + state.page = action.payload.page + }, purchaseContentFlowFailed: ( state, action: PayloadAction<{ error: PurchaseContentError }> diff --git a/packages/common/src/store/purchase-content/types.ts b/packages/common/src/store/purchase-content/types.ts index dc311beb6bb..70ba7d55d07 100644 --- a/packages/common/src/store/purchase-content/types.ts +++ b/packages/common/src/store/purchase-content/types.ts @@ -15,6 +15,11 @@ export enum PurchaseContentStage { FINISH = 'FINISH' } +export enum PurchaseContentPage { + PURCHASE = 'purchase', + TRANSFER = 'crypto-transfer' +} + export enum PurchaseErrorCode { Canceled = 'Canceled', InsufficientBalance = 'InsufficientBalance', diff --git a/packages/common/src/store/ui/modals/usdc-manual-transfer-modal/index.ts b/packages/common/src/store/ui/modals/usdc-manual-transfer-modal/index.ts index 5113e596983..61ce1f10619 100644 --- a/packages/common/src/store/ui/modals/usdc-manual-transfer-modal/index.ts +++ b/packages/common/src/store/ui/modals/usdc-manual-transfer-modal/index.ts @@ -1,11 +1,6 @@ -import { Action } from 'redux' - import { createModal } from '../createModal' -export type USDCManualTransferModalState = { - amount?: number - onSuccessAction?: Action -} +export type USDCManualTransferModalState = {} const USDCManualTransferModal = createModal({ reducerPath: 'USDCManualTransferModal', diff --git a/packages/mobile/src/components/premium-track-purchase-drawer/PremiumTrackPurchaseDrawer.tsx b/packages/mobile/src/components/premium-track-purchase-drawer/PremiumTrackPurchaseDrawer.tsx index 6eb4fcdb5f3..fd897ce631b 100644 --- a/packages/mobile/src/components/premium-track-purchase-drawer/PremiumTrackPurchaseDrawer.tsx +++ b/packages/mobile/src/components/premium-track-purchase-drawer/PremiumTrackPurchaseDrawer.tsx @@ -5,6 +5,7 @@ import type { PurchaseContentError } from '@audius/common' import { + PurchaseContentPage, FeatureFlags, Name, PURCHASE_METHOD, @@ -50,6 +51,7 @@ import { useThemeColors } from 'app/utils/theme' import LoadingSpinner from '../loading-spinner/LoadingSpinner' import { PaymentMethod } from '../payment-method/PaymentMethod' import { TrackDetailsTile } from '../track-details-tile' +import { USDCManualTransfer } from '../usdc-manual-transfer' import { AudioMatchSection } from './AudioMatchSection' import { PayExtraFormSection } from './PayExtraFormSection' @@ -61,6 +63,7 @@ import { usePurchaseSummaryValues } from './hooks/usePurchaseSummaryValues' const { getPurchaseContentFlowStage, getPurchaseContentError } = purchaseContentSelectors +const { setPurchasePage } = purchaseContentActions const messages = { buy: 'Buy', @@ -151,6 +154,9 @@ const useStyles = makeStyles(({ spacing, typography, palette }) => ({ }, bottomSection: { gap: spacing(6) + }, + paddingTop: { + paddingTop: spacing(4) } })) @@ -219,6 +225,7 @@ const RenderForm = ({ }) => { const navigation = useNavigation() const styles = useStyles() + const dispatch = useDispatch() const { specialLightGreen, primary } = useThemeColors() const presetValues = usePayExtraPresets() const { isEnabled: isIOSUSDCPurchaseEnabled } = useFeatureFlag( @@ -253,7 +260,7 @@ const RenderForm = ({ setMethod: setPurchaseMethod }) - const { stage, error, isUnlocking, purchaseSummaryValues } = + const { page, stage, error, isUnlocking, purchaseSummaryValues } = usePurchaseContentFormState({ price }) const { amountDue } = purchaseSummaryValues @@ -271,7 +278,11 @@ const RenderForm = ({ trackEvent(make({ eventName: Name.PURCHASE_CONTENT_TOS_CLICKED })) }, []) - return ( + const handleUSDCManualTransferClose = useCallback(() => { + dispatch(setPurchasePage({ page: PurchaseContentPage.PURCHASE })) + }, [dispatch]) + + return page === PurchaseContentPage.PURCHASE ? ( <> {stage !== PurchaseContentStage.FINISH ? ( @@ -340,6 +351,14 @@ const RenderForm = ({ )} + ) : ( + + + ) } diff --git a/packages/mobile/src/components/premium-track-purchase-drawer/hooks/usePurchaseContentFormState.ts b/packages/mobile/src/components/premium-track-purchase-drawer/hooks/usePurchaseContentFormState.ts index 8f574de4b7a..cd82c230e16 100644 --- a/packages/mobile/src/components/premium-track-purchase-drawer/hooks/usePurchaseContentFormState.ts +++ b/packages/mobile/src/components/premium-track-purchase-drawer/hooks/usePurchaseContentFormState.ts @@ -9,10 +9,14 @@ import { useSelector } from 'react-redux' import { usePurchaseSummaryValues } from './usePurchaseSummaryValues' -const { getPurchaseContentFlowStage, getPurchaseContentError } = - purchaseContentSelectors +const { + getPurchaseContentFlowStage, + getPurchaseContentError, + getPurchaseContentPage +} = purchaseContentSelectors export const usePurchaseContentFormState = ({ price }: { price: number }) => { + const page = useSelector(getPurchaseContentPage) const stage = useSelector(getPurchaseContentFlowStage) const error = useSelector(getPurchaseContentError) const isUnlocking = !error && isContentPurchaseInProgress(stage) @@ -32,6 +36,7 @@ export const usePurchaseContentFormState = ({ price }: { price: number }) => { }) return { + page, stage, error, isUnlocking, diff --git a/packages/mobile/src/components/usdc-manual-transfer-drawer/USDCManualTransferDrawer.tsx b/packages/mobile/src/components/usdc-manual-transfer-drawer/USDCManualTransferDrawer.tsx index 5fb344b78e1..fbf63dfef73 100644 --- a/packages/mobile/src/components/usdc-manual-transfer-drawer/USDCManualTransferDrawer.tsx +++ b/packages/mobile/src/components/usdc-manual-transfer-drawer/USDCManualTransferDrawer.tsx @@ -1,53 +1,14 @@ -import { useCallback, useMemo } from 'react' - -import { - Name, - isContentPurchaseInProgress, - purchaseContentSelectors, - useCreateUserbankIfNeeded, - useUSDCBalance, - useUSDCManualTransferModal -} from '@audius/common' -import { USDC } from '@audius/fixed-decimal' -import Clipboard from '@react-native-clipboard/clipboard' -import BN from 'bn.js' +import { useUSDCManualTransferModal } from '@audius/common' import { View } from 'react-native' -import QRCode from 'react-qr-code' -import { useDispatch, useSelector } from 'react-redux' -import { useAsync } from 'react-use' -import IconError from 'app/assets/images/iconError.svg' -import LogoUSDC from 'app/assets/images/logoUSDC.svg' -import { Button, Text, useLink } from 'app/components/core' +import { Text } from 'app/components/core' import Drawer from 'app/components/drawer' -import { useToast } from 'app/hooks/useToast' -import { make, track, track as trackEvent } from 'app/services/analytics' -import { audiusBackendInstance } from 'app/services/audius-backend-instance' -import { getUSDCUserBank } from 'app/services/buyCrypto' import { flexRowCentered, makeStyles } from 'app/styles' -import { spacing } from 'app/styles/spacing' -import type { AllEvents } from 'app/types/analytics' -import { useThemeColors } from 'app/utils/theme' - -import { AddressTile } from '../core/AddressTile' - -const { getPurchaseContentFlowStage, getPurchaseContentError } = - purchaseContentSelectors -const USDCLearnMore = - 'https://support.audius.co/help/Understanding-USDC-on-Audius' +import { USDCManualTransfer } from '../usdc-manual-transfer/USDCManualTransfer' const messages = { - title: 'Manual Crypto Transfer', - explainer: - 'Add funds by sending Solana based (SPL) USDC to your Audius account.', - hint: 'Use caution to avoid errors and lost funds.', - copy: 'Copy Wallet Address', - goBack: 'Go Back', - learnMore: 'Learn More', - copied: 'Copied to Clipboard!', - usdcBalance: 'USDC Balance', - buy: (amount: string) => `Buy ${amount}` + title: 'Manual Crypto Transfer' } const useStyles = makeStyles(({ spacing, palette, typography }) => ({ @@ -63,102 +24,12 @@ const useStyles = makeStyles(({ spacing, palette, typography }) => ({ paddingBottom: spacing(4), borderBottomWidth: 1, borderBottomColor: palette.neutralLight8 - }, - disclaimerContainer: { - display: 'flex', - alignItems: 'flex-start', - flexDirection: 'row', - paddingHorizontal: spacing(4), - paddingVertical: spacing(3), - backgroundColor: palette.backgroundSurface2, - borderColor: palette.borderStrong, - borderWidth: 1, - borderRadius: spacing(2), - gap: spacing(4) - }, - disclaimer: { - lineHeight: typography.fontSize.medium * 1.25 - }, - icon: { - marginTop: spacing(2) - }, - buttonContainer: { - gap: spacing(2) - }, - learnMore: { - textDecorationLine: 'underline' - }, - explainer: { - textAlign: 'left', - lineHeight: typography.fontSize.medium * 1.25 - }, - hintContainer: { - gap: spacing(3), - flexShrink: 1 - }, - shrink: { - flexShrink: 1 - }, - qr: { - justifyContent: 'center', - alignItems: 'center', - padding: 10 } })) export const USDCManualTransferDrawer = () => { const styles = useStyles() - const dispatch = useDispatch() - const { toast } = useToast() - const { isOpen, onClose, onClosed, data } = useUSDCManualTransferModal() - const { amount: amountInCents, onSuccessAction } = data ?? {} - const { onPress: onPressLearnMore } = useLink(USDCLearnMore) - const { neutral, specialLightGreen } = useThemeColors() - - const stage = useSelector(getPurchaseContentFlowStage) - const error = useSelector(getPurchaseContentError) - const isUnlocking = !error && isContentPurchaseInProgress(stage) - const { data: balanceBN } = useUSDCBalance({ - isPolling: true, - pollingInterval: 1000 - }) - const balance = USDC(balanceBN ?? new BN(0)).value - const amount = USDC((amountInCents ?? 0) / 100).value - const isBuyButtonDisabled = isUnlocking || balance < amount - - useCreateUserbankIfNeeded({ - recordAnalytics: track, - audiusBackendInstance, - mint: 'usdc' - }) - - const { value: USDCUserBank } = useAsync(async () => { - const USDCUserBankPubKey = await getUSDCUserBank() - return USDCUserBankPubKey?.toString() ?? '' - }) - - const analytics: AllEvents = useMemo( - () => ({ - eventName: Name.PURCHASE_CONTENT_USDC_USER_BANK_COPIED, - address: USDCUserBank ?? '' - }), - [USDCUserBank] - ) - - const handleConfirmPress = useCallback(() => { - Clipboard.setString(USDCUserBank ?? '') - toast({ content: messages.copied, type: 'info' }) - trackEvent(make(analytics)) - }, [USDCUserBank, analytics, toast]) - - const handleLearnMorePress = useCallback(() => { - onPressLearnMore() - }, [onPressLearnMore]) - - const handleBuyPress = useCallback(() => { - if (onSuccessAction) dispatch(onSuccessAction) - onClose() - }, [dispatch, onClose, onSuccessAction]) + const { isOpen, onClose, onClosed } = useUSDCManualTransferModal() return ( @@ -174,82 +45,7 @@ export const USDCManualTransferDrawer = () => { {messages.title} - {messages.explainer} - - {USDCUserBank ? ( - - ) : null} - - } - analytics={analytics} - balance={USDC(balanceBN ?? new BN(0)).toLocaleString('en-US', { - roundingMode: 'floor', - minimumFractionDigits: 2, - maximumFractionDigits: 2 - })} - /> - - - - - {messages.hint} - - - {messages.learnMore} - - - - - {amountInCents === undefined ? ( - <> -