Skip to content

Commit

Permalink
[PAY-2329] Use download_conditions in purchase flow (#7385)
Browse files Browse the repository at this point in the history
  • Loading branch information
dharit-tan authored Feb 5, 2024
1 parent c792f8b commit e513ff3
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 49 deletions.
10 changes: 9 additions & 1 deletion packages/common/src/hooks/purchaseContent/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,18 @@ export enum PayExtraPreset {
NONE = 'none'
}

export type PurchaseableTrackMetadata = UserTrackMetadata & {
export type PurchaseableTrackStreamMetadata = UserTrackMetadata & {
stream_conditions: USDCPurchaseConditions
}

export type PurchaseableTrackDownloadMetadata = UserTrackMetadata & {
download_conditions: USDCPurchaseConditions
}

export type PurchaseableTrackMetadata =
| PurchaseableTrackStreamMetadata
| PurchaseableTrackDownloadMetadata

export type USDCPurchaseConfig = {
minContentPriceCents: number
maxContentPriceCents: number
Expand Down
12 changes: 9 additions & 3 deletions packages/common/src/hooks/purchaseContent/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { UserTrackMetadata, isContentUSDCPurchaseGated } from '~/models/Track'
import {
PayExtraAmountPresetValues,
PayExtraPreset,
PurchaseableTrackMetadata
PurchaseableTrackDownloadMetadata,
PurchaseableTrackStreamMetadata
} from './types'

type GetExtraAmountArgs = {
Expand Down Expand Up @@ -33,7 +34,12 @@ export const getExtraAmount = ({
return extraAmount
}

export const isTrackPurchaseable = (
export const isTrackStreamPurchaseable = (
track: UserTrackMetadata
): track is PurchaseableTrackMetadata =>
): track is PurchaseableTrackStreamMetadata =>
isContentUSDCPurchaseGated(track.stream_conditions)

export const isTrackDownloadPurchaseable = (
track: UserTrackMetadata
): track is PurchaseableTrackDownloadMetadata =>
isContentUSDCPurchaseGated(track.download_conditions)
28 changes: 12 additions & 16 deletions packages/common/src/store/purchase-content/sagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,20 +92,18 @@ function* getContentInfo({ contentId, contentType }: GetPurchaseConfigArgs) {
}

const trackInfo = yield* select(getTrack, { id: contentId })
if (!trackInfo || !isContentUSDCPurchaseGated(trackInfo?.stream_conditions)) {
throw new Error('Content is missing stream conditions')
const purchaseConditions =
trackInfo?.stream_conditions ?? trackInfo?.download_conditions
if (!trackInfo || !isContentUSDCPurchaseGated(purchaseConditions)) {
throw new Error('Content is missing purchase conditions')
}
const artistInfo = yield* select(getUser, { id: trackInfo.owner_id })
if (!artistInfo) {
throw new Error('Failed to retrieve content owner')
}

const {
stream_conditions: {
usdc_purchase: { price }
},
title
} = trackInfo
const title = trackInfo.title
const price = purchaseConditions.usdc_purchase.price

return { price, title, artistInfo, trackInfo }
}
Expand Down Expand Up @@ -202,8 +200,10 @@ function* getPurchaseConfig({ contentId, contentType }: GetPurchaseConfigArgs) {
}

const trackInfo = yield* select(getTrack, { id: contentId })
if (!trackInfo || !isContentUSDCPurchaseGated(trackInfo?.stream_conditions)) {
throw new Error('Content is missing stream conditions')
const purchaseConditions =
trackInfo?.stream_conditions ?? trackInfo?.download_conditions
if (!trackInfo || !isContentUSDCPurchaseGated(purchaseConditions)) {
throw new Error('Content is missing purchase conditions')
}

const user = yield* select(getUser, { id: trackInfo.owner_id })
Expand All @@ -215,12 +215,8 @@ function* getPurchaseConfig({ contentId, contentType }: GetPurchaseConfigArgs) {
throw new Error('Unable to resolve destination wallet')
}

const {
blocknumber,
stream_conditions: {
usdc_purchase: { splits }
}
} = trackInfo
const { blocknumber } = trackInfo
const splits = purchaseConditions.usdc_purchase.splits

return {
blocknumber,
Expand Down
3 changes: 3 additions & 0 deletions packages/libs/src/services/solana/SolanaWeb3Manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,9 @@ export class SolanaWeb3Manager {
'A web3Manager is required for this solanaWeb3Manager method'
)
}
if (!splits) {
throw new Error('Splits must be provided')
}
if (Object.values(splits).length !== 1) {
throw new Error(
'Purchasing content only supports a single split. Specifying more splits coming soon!'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import {
usePurchaseContentFormConfiguration,
usePurchaseContentErrorMessage,
usePayExtraPresets,
isTrackPurchaseable,
PURCHASE_METHOD,
PURCHASE_VENDOR,
usePurchaseMethod
usePurchaseMethod,
isTrackStreamPurchaseable,
isTrackDownloadPurchaseable
} from '@audius/common/hooks'
import type { PurchaseableTrackMetadata } from '@audius/common/hooks'
import type { USDCPurchaseConditions } from '@audius/common/models'
import {
Name,
PurchaseVendor,
Expand Down Expand Up @@ -227,10 +229,12 @@ const getButtonText = (isUnlocking: boolean, amountDue: number) =>
// of the `<Formik />` component
const RenderForm = ({
onClose,
track
track,
purchaseConditions
}: {
onClose: () => void
track: PurchaseableTrackMetadata
purchaseConditions: USDCPurchaseConditions
}) => {
const navigation = useNavigation()
const styles = useStyles()
Expand All @@ -248,10 +252,8 @@ const RenderForm = ({
useEffect(() => resetForm, [track.track_id, resetForm])

const {
stream_conditions: {
usdc_purchase: { price }
}
} = track
usdc_purchase: { price }
} = purchaseConditions

const [{ value: purchaseMethod }, , { setValue: setPurchaseMethod }] =
useField(PURCHASE_METHOD)
Expand Down Expand Up @@ -432,10 +434,18 @@ export const PremiumTrackPurchaseDrawer = () => {

const isLoading = statusIsNotFinalized(trackStatus)

const isValidTrack = track && isTrackPurchaseable(track)
const price = isValidTrack
? track?.stream_conditions?.usdc_purchase?.price
: 0
const isValidStreamGatedTrack = !!track && isTrackStreamPurchaseable(track)
const isValidDownloadGatedTrack =
!!track && isTrackDownloadPurchaseable(track)

const purchaseConditions = isValidStreamGatedTrack
? track.stream_conditions
: isValidDownloadGatedTrack
? track.download_conditions
: null

const price = purchaseConditions ? purchaseConditions?.usdc_purchase.price : 0

const { initialValues, onSubmit, validationSchema } =
usePurchaseContentFormConfiguration({ track, presetValues, price })

Expand All @@ -444,7 +454,15 @@ export const PremiumTrackPurchaseDrawer = () => {
dispatch(purchaseContentActions.cleanup())
}, [onClosed, dispatch])

if (!track || !isTrackPurchaseable(track) || !isUSDCEnabled) return null
if (
!track ||
!purchaseConditions ||
!isUSDCEnabled ||
!(isValidStreamGatedTrack || isValidDownloadGatedTrack)
) {
console.error('PremiumContentPurchaseModal: Track is not purchasable')
return null
}

return (
<Drawer
Expand All @@ -467,7 +485,11 @@ export const PremiumTrackPurchaseDrawer = () => {
validationSchema={toFormikValidationSchema(validationSchema)}
onSubmit={onSubmit}
>
<RenderForm onClose={onClose} track={track} />
<RenderForm
onClose={onClose}
track={track}
purchaseConditions={purchaseConditions}
/>
</Formik>
</View>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { useCallback, useEffect } from 'react'
import { useIsUSDCEnabled } from 'hooks/useIsUSDCEnabled'

import { useGetTrackById } from '@audius/common/api'
import {
PurchaseableTrackMetadata,
useFeatureFlag,
usePurchaseContentFormConfiguration,
usePayExtraPresets,
isTrackPurchaseable
isTrackStreamPurchaseable,
isTrackDownloadPurchaseable,
PurchaseableTrackMetadata
} from '@audius/common/hooks'
import { PurchaseVendor, Track } from '@audius/common/models'
import {
PurchaseVendor,
Track,
USDCPurchaseConditions
} from '@audius/common/models'
import { FeatureFlags } from '@audius/common/services'
import {
buyUSDCActions,
Expand Down Expand Up @@ -68,19 +74,19 @@ const pageToPageIndex = (page: PurchaseContentPage) => {
// of the `<Formik />` component
const RenderForm = ({
onClose,
track
track,
purchaseConditions
}: {
onClose: () => void
track: PurchaseableTrackMetadata
purchaseConditions: USDCPurchaseConditions
}) => {
const dispatch = useDispatch()
const isMobile = useIsMobile()
const { permalink } = track
const {
permalink,
stream_conditions: {
usdc_purchase: { price }
}
} = track
usdc_purchase: { price }
} = purchaseConditions
const { error, isUnlocking, purchaseSummaryValues, stage, page } =
usePurchaseContentFormState({ price })
const currentPageIndex = pageToPageIndex(page)
Expand Down Expand Up @@ -177,6 +183,7 @@ export const PremiumContentPurchaseModal = () => {
} = usePremiumContentPurchaseModal()
const { isEnabled: isCoinflowEnabled, isLoaded: isCoinflowEnabledLoaded } =
useFeatureFlag(FeatureFlags.BUY_WITH_COINFLOW)
const isUSDCEnabled = useIsUSDCEnabled()
const stage = useSelector(getPurchaseContentFlowStage)
const error = useSelector(getPurchaseContentError)
const isUnlocking = !error && isContentPurchaseInProgress(stage)
Expand All @@ -187,10 +194,18 @@ export const PremiumContentPurchaseModal = () => {
{ disabled: !trackId }
)

const isValidTrack = track && isTrackPurchaseable(track)
const price = isValidTrack
? track?.stream_conditions?.usdc_purchase?.price
: 0
const isValidStreamGatedTrack = !!track && isTrackStreamPurchaseable(track)
const isValidDownloadGatedTrack =
!!track && isTrackDownloadPurchaseable(track)

const purchaseConditions = isValidStreamGatedTrack
? track.stream_conditions
: isValidDownloadGatedTrack
? track.download_conditions
: null

const price = purchaseConditions ? purchaseConditions?.usdc_purchase.price : 0

const { initialValues, validationSchema, onSubmit } =
usePurchaseContentFormConfiguration({
track,
Expand Down Expand Up @@ -219,8 +234,13 @@ export const PremiumContentPurchaseModal = () => {
dispatch(cleanupUSDCRecovery())
}, [onClosed, dispatch])

if (track && !isValidTrack) {
if (
!track ||
!purchaseConditions ||
!(isValidDownloadGatedTrack || isValidStreamGatedTrack)
) {
console.error('PremiumContentPurchaseModal: Track is not purchasable')
return null
}

return (
Expand All @@ -235,13 +255,17 @@ export const PremiumContentPurchaseModal = () => {
zIndex={zIndex.PREMIUM_CONTENT_PURCHASE_MODAL}
wrapperClassName={isMobile ? styles.mobileWrapper : undefined}
>
{isValidTrack && isCoinflowEnabledLoaded ? (
{isCoinflowEnabledLoaded && isUSDCEnabled ? (
<Formik
initialValues={initialValues}
validationSchema={toFormikValidationSchema(validationSchema)}
onSubmit={onSubmit}
>
<RenderForm track={track} onClose={handleClose} />
<RenderForm
track={track}
onClose={handleClose}
purchaseConditions={purchaseConditions}
/>
</Formik>
) : null}
</ModalDrawer>
Expand Down

0 comments on commit e513ff3

Please sign in to comment.