Skip to content
Merged
238 changes: 213 additions & 25 deletions packages/web/src/pages/chat-page/components/TargetedMessageModal.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { useMemo } from 'react'

import { useGetCurrentUser, useGetUserTracksByHandle } from '@audius/common/api'
import { isContentUSDCPurchaseGated } from '@audius/common/models'
import { useTargetedMessageModal } from '@audius/common/src/store/ui/modals/create-targeted-message-modal'
import {
Flex,
Expand All @@ -11,40 +15,52 @@ import {
RadioGroup,
ModalFooter,
IconCaretLeft,
ModalContent
ModalContent,
Select
} from '@audius/harmony'
import { Formik, FormikValues, useField } from 'formik'

const messages = {
title: 'Target Audience',
back: 'Back',
continue: 'Continue'
}

const targetAudienceOptions = [
{
continue: 'Continue',
followers: {
label: 'My Followers',
value: 'followers'
description: 'Send a bulk message to all of your followers.'
},
{
supporters: {
label: 'Tip Supporters',
value: 'supporters'
description: 'Send a bulk message to everyone who has tipped you.'
},
{
purchasers: {
label: 'Past Purchasers',
value: 'purchasers'
description:
'Send a bulk message to everyone who has purchased content from you on Audius.',
placeholder: 'Premium Content'
},
{
remixCreators: {
label: 'Remix Creators',
value: 'remix_creators'
description:
'Send a bulk message to creators who have remixed your tracks.',
placeholder: 'Tracks with Remixes'
}
]
}

const TARGET_AUDIENCE_FIELD = 'target_audience'

type TargetedMessageFormValues = {
target_audience: 'followers' | 'supporters' | 'purchasers' | 'remix_creators'
purchased_track_id?: string
remixed_track_id?: string
}

export const TargetedMessageModal = () => {
const { isOpen, onClose } = useTargetedMessageModal()

const initialValues = {
target_audience: undefined
const initialValues: TargetedMessageFormValues = {
target_audience: 'followers',
purchased_track_id: undefined,
remixed_track_id: undefined
}

const handleSubmit = (values: FormikValues) => {
Expand All @@ -69,7 +85,10 @@ export const TargetedMessageModal = () => {

return (
<Modal size='small' isOpen={isOpen} onClose={onClose}>
<Formik initialValues={initialValues} onSubmit={handleSubmit}>
<Formik<TargetedMessageFormValues>
initialValues={initialValues}
onSubmit={handleSubmit}
>
{({ submitForm }) => (
<>
<ModalHeader>
Expand Down Expand Up @@ -109,20 +128,189 @@ export const TargetedMessageModal = () => {
}

const TargetedMessagesFields = () => {
const [field] = useField('target_audience')
const [field] = useField(TARGET_AUDIENCE_FIELD)

return (
<RadioGroup {...field}>
<Flex direction='column' gap='xl'>
{targetAudienceOptions.map(({ label, value }) => (
<Flex as='label' gap='s' key={label}>
<Radio value={value} />
<Text variant='title' size='l'>
{label}
<FollowersMessageField />
<TipSupportersMessageField />
<PastPurchasersMessageField />
<RemixCreatorsMessageField />
</Flex>
</RadioGroup>
)
}

const FollowersMessageField = () => {
const { data: user } = useGetCurrentUser()
const { follower_count: followerCount } = user ?? {}
const [{ value }] = useField(TARGET_AUDIENCE_FIELD)
const selected = value === 'followers'
return (
<Flex as='label' gap='l'>
<Radio value='followers' />
<Flex direction='column' gap='xs'>
<Flex gap='xs'>
<Text variant='title' size='l'>
{messages.followers.label}
</Text>
{selected ? (
<Text variant='title' size='l' color='subdued'>
({followerCount ?? 0})
</Text>
) : null}
</Flex>
{selected ? (
<Text size='s'>{messages.followers.description}</Text>
) : null}
</Flex>
</Flex>
)
}

const TipSupportersMessageField = () => {
const { data: user } = useGetCurrentUser()
const { supporter_count: supporterCount } = user ?? {}
const [{ value }] = useField(TARGET_AUDIENCE_FIELD)
const selected = value === 'supporters'
return (
<Flex as='label' gap='l'>
<Radio value='supporters' />
<Flex direction='column' gap='xs'>
<Flex gap='xs'>
<Text variant='title' size='l'>
{messages.supporters.label}
</Text>
{selected ? (
<Text variant='title' size='l' color='subdued'>
({supporterCount ?? 0})
</Text>
) : null}
</Flex>
{selected ? (
<Text size='s'>{messages.supporters.description}</Text>
) : null}
</Flex>
</Flex>
)
}

const PastPurchasersMessageField = () => {
const { data: user } = useGetCurrentUser()
const {
// TODO: Need to add a new endpoint to get the list of past purchasers
supporter_count: supporterCount,
handle,
user_id: currentUserId
} = user ?? {}
const [{ value }] = useField(TARGET_AUDIENCE_FIELD)
const [purchasedTrackField, , { setValue: setPurchasedTrackId }] = useField({
name: 'purchased_track_id',
type: 'select'
})

const isSelected = value === 'purchasers'

const { data: tracks } = useGetUserTracksByHandle({ handle, currentUserId })
const premiumTrackOptions = useMemo(
() =>
(tracks ?? [])
.filter(
(track) =>
isContentUSDCPurchaseGated(track.stream_conditions) ||
isContentUSDCPurchaseGated(track.download_conditions)
)
.map((track) => ({
value: track.track_id.toString(),
label: track.title
})),
[tracks]
)

return (
<Flex as='label' gap='l'>
<Radio value='purchasers' />
<Flex direction='column' gap='xs'>
<Flex gap='xs'>
<Text variant='title' size='l'>
{messages.purchasers.label}
</Text>
{isSelected ? (
<Text variant='title' size='l' color='subdued'>
({supporterCount ?? 0})
</Text>
) : null}
</Flex>
{isSelected ? (
<Flex direction='column' gap='l'>
<Text size='s'>{messages.purchasers.description}</Text>
<Select
{...purchasedTrackField}
options={premiumTrackOptions}
label={messages.purchasers.placeholder}
onChange={setPurchasedTrackId}
/>
</Flex>
))}
) : null}
</Flex>
</RadioGroup>
</Flex>
)
}

const RemixCreatorsMessageField = () => {
const { data: user } = useGetCurrentUser()
const { handle, user_id: currentUserId } = user ?? {}
const [{ value }] = useField(TARGET_AUDIENCE_FIELD)
const [remixedTrackField, , { setValue: setRemixedTrackId }] = useField({
name: 'remixed_track_id',
type: 'select'
})

const isSelected = value === 'remix_creators'

const { data: tracks } = useGetUserTracksByHandle({ handle, currentUserId })
const premiumTrackOptions = useMemo(
() =>
(tracks ?? [])
.filter((track) => {
// TODO: get tracks with remixes
return true
})
.map((track) => ({
value: track.track_id.toString(),
label: track.title
})),
[tracks]
)

return (
<Flex as='label' gap='l'>
<Radio value='remix_creators' />
<Flex direction='column' gap='xs'>
<Flex gap='xs'>
<Text variant='title' size='l'>
{messages.remixCreators.label}
</Text>
{isSelected ? (
<Text variant='title' size='l' color='subdued'>
{/* TODO: Need to add a new endpoint to get the list of tracks with remixes and their creators */}
({0})
</Text>
) : null}
</Flex>
{isSelected ? (
<Flex direction='column' gap='l'>
<Text size='s'>{messages.remixCreators.description}</Text>
<Select
{...remixedTrackField}
options={premiumTrackOptions}
label={messages.remixCreators.placeholder}
onChange={setRemixedTrackId}
/>
</Flex>
) : null}
</Flex>
</Flex>
)
}