Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/mobile/src/app/Drawers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { HostRemixContestDrawer } from 'app/components/host-remix-contest-drawer
import { InboxUnavailableDrawer } from 'app/components/inbox-unavailable-drawer/InboxUnavailableDrawer'
import { LeavingAudiusDrawer } from 'app/components/leaving-audius-drawer'
import { LockedContentDrawer } from 'app/components/locked-content-drawer'
import { LockedTextPostDrawer } from 'app/components/locked-text-post-drawer'
import { ManagerModeDrawer } from 'app/components/manager-mode-drawer/ManagerModeDrawer'
import { OverflowMenuDrawer } from 'app/components/overflow-menu-drawer'
import { PlaybackRateDrawer } from 'app/components/playback-rate-drawer'
Expand Down Expand Up @@ -163,6 +164,7 @@ const nativeDrawersMap: { [DrawerName in Drawer]?: ComponentType } = {
RemoveDownloadedFavorites: RemoveDownloadedFavoritesDrawer,
UnfavoriteDownloadedCollection: UnfavoriteDownloadedCollectionDrawer,
LockedContent: LockedContentDrawer,
LockedTextPost: LockedTextPostDrawer,
ChatActions: ChatActionsDrawer,
CreateChatActions: CreateChatActionsDrawer,
BlockMessages: BlockMessagesDrawer,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import { useCallback } from 'react'

import { useArtistCoin } from '@audius/common/api'
import type {
ID,
AccessConditions,
TokenGatedConditions
} from '@audius/common/models'
import type { ID, AccessConditions } from '@audius/common/models'
import {
ModalSource,
isContentTokenGated,
Expand Down Expand Up @@ -33,7 +28,6 @@ import {
} from '@audius/harmony-native'
import LoadingSpinner from 'app/components/loading-spinner'
import { useIsUSDCEnabled } from 'app/hooks/useIsUSDCEnabled'
import { useNavigation } from 'app/hooks/useNavigation'
import { make, track } from 'app/services/analytics'
import { setVisibility } from 'app/store/drawers/slice'
import { makeStyles } from 'app/styles'
Expand Down Expand Up @@ -84,12 +78,6 @@ export const LineupTileAccessStatus = ({
isUSDCEnabled && isContentUSDCPurchaseGated(streamConditions)
const isTokenGated = isContentTokenGated(streamConditions)
const isUnlocking = gatedTrackStatus === 'UNLOCKING'
const navigation = useNavigation()

const { data: token } = useArtistCoin(
(streamConditions as TokenGatedConditions)?.token_gate?.token_mint,
{ enabled: isTokenGated }
)

const handlePress = useCallback(() => {
if (hasStreamAccess) {
Expand Down Expand Up @@ -120,27 +108,17 @@ export const LineupTileAccessStatus = ({
source: determineModalSource()
}
)
} else if (isTokenGated) {
if (token?.ticker) {
navigation.push('BuySell', {
initialTab: 'buy',
coinTicker: token.ticker
})
}
} else if (contentId) {
dispatch(setLockedContentId({ id: contentId }))
dispatch(setVisibility({ drawer: 'LockedContent', visible: true }))
}
}, [
hasStreamAccess,
isUSDCPurchase,
isTokenGated,
contentId,
contentType,
openPremiumContentPurchaseModal,
tileSource,
token?.ticker,
navigation,
dispatch
])

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { useCallback } from 'react'

import { useArtistCoin } from '@audius/common/api'
import { View } from 'react-native'

import { Button, Flex, IconLock, Text } from '@audius/harmony-native'
import { NativeDrawer } from 'app/components/drawer'
import { useDrawer } from 'app/hooks/useDrawer'
import { useNavigation } from 'app/hooks/useNavigation'
import { makeStyles, flexRowCentered } from 'app/styles'
import { spacing } from 'app/styles/spacing'
import { useColor } from 'app/utils/theme'

const DRAWER_NAME = 'LockedTextPost'

const messages = {
howToUnlock: 'HOW TO UNLOCK',
description: 'To unlock this post, you need to hold',
buyCoins: 'Buy Coins'
}

const useStyles = makeStyles(({ spacing, palette }) => ({
drawer: {
paddingVertical: spacing(6),
alignItems: 'center',
backgroundColor: palette.white,
paddingHorizontal: spacing(4),
gap: spacing(6)
},
titleContainer: {
...flexRowCentered(),
justifyContent: 'center',
paddingBottom: spacing(4),
gap: spacing(2),
borderBottomColor: palette.neutralLight8,
borderBottomWidth: 1,
width: '100%'
}
}))

export const LockedTextPostDrawer = () => {
const styles = useStyles()
const neutralLight2 = useColor('neutralLight2')
const navigation = useNavigation()
const { data, onClose } = useDrawer('LockedTextPost')
const mint = (data as { mint: string } | undefined)?.mint
const { data: coin } = useArtistCoin(mint)

const handleBuyCoins = useCallback(() => {
if (coin?.ticker) {
onClose()
navigation.navigate('BuySell', {
initialTab: 'buy',
coinTicker: coin.ticker
})
}
}, [coin?.ticker, navigation, onClose])

return (
<NativeDrawer drawerName={DRAWER_NAME}>
<View style={styles.drawer}>
<View style={styles.titleContainer}>
<IconLock
fill={neutralLight2}
width={spacing(6)}
height={spacing(6)}
/>
<Text variant='label' size='xl' strength='strong' color='subdued'>
{messages.howToUnlock}
</Text>
</View>
<Flex column gap='l' w='100%' alignItems='center' ph='l'>
<Text variant='body' size='l' textAlign='center'>
{messages.description}{' '}
<Text variant='body' size='l' strength='strong'>
{coin?.ticker ? `$${coin.ticker}` : "the artist's coins"}
</Text>
.
</Text>
<Button
variant='primary'
color='coinGradient'
fullWidth
onPress={handleBuyCoins}
>
{messages.buyCoins}
</Button>
</Flex>
</View>
</NativeDrawer>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { LockedTextPostDrawer } from './LockedTextPostDrawer'
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,11 @@ const FanClubFeed = ({ mint }: { mint: string }) => {

{hasTextPosts
? textPosts.map((item) => (
<TextPostCard key={item.commentId} commentId={item.commentId} />
<TextPostCard
key={item.commentId}
commentId={item.commentId}
mint={mint}
/>
))
: null}

Expand Down Expand Up @@ -377,9 +381,7 @@ export const FanClubTab = ({ mint, onSwitchToCoinTab }: FanClubTabProps) => {
<CoinLeaderboardCard mint={mint} />
) : null}

{membershipKnown ? (
<FanClubFeed mint={mint} />
) : null}
{membershipKnown ? <FanClubFeed mint={mint} /> : null}
</Flex>
)
}
Original file line number Diff line number Diff line change
@@ -1,53 +1,38 @@
import { useCallback } from 'react'

import { useComment } from '@audius/common/api'
import type { ID } from '@audius/common/models'
import { getLargestTimeUnitText } from '@audius/common/utils'
import { View } from 'react-native'
import LinearGradient from 'react-native-linear-gradient'

import {
Button,
Flex,
IconLock,
Paper,
Skeleton,
Text,
useTheme
Text
} from '@audius/harmony-native'
import { ProfilePicture } from 'app/components/core'
import { UserLink } from 'app/components/user-link'
import { useDrawer } from 'app/hooks/useDrawer'

const messages = {
unlock: 'Unlock',
membersOnly: 'Members Only'
}

/**
* Generate a deterministic pseudo-random placeholder string for locked posts
* so each post looks visually distinct behind the blur.
*/
const generatePlaceholder = (commentId: ID) => {
const seed = Number(commentId)
const wordCount = 5 + (seed % 21) // 5–25 words
const words: string[] = []
const pool = 'abcdefghijklmnopqrstuvwxyz'
for (let i = 0; i < wordCount; i++) {
const len = 3 + ((seed * (i + 1) * 7) % 8) // 3–10 chars per word
let word = ''
for (let j = 0; j < len; j++) {
word += pool[(seed * (i + 1) * (j + 1) * 13) % pool.length]
}
words.push(word)
}
return words.join(' ')
}

type TextPostCardProps = {
commentId: ID
mint: string
}

export const TextPostCard = ({ commentId }: TextPostCardProps) => {
export const TextPostCard = ({ commentId, mint }: TextPostCardProps) => {
const { data: comment, isPending } = useComment(commentId)
const { color } = useTheme()
const { onOpen: openLockedTextPostDrawer } = useDrawer('LockedTextPost')

const handleUnlock = useCallback(() => {
openLockedTextPostDrawer({ mint })
}, [openLockedTextPostDrawer, mint])

if (isPending) {
return (
Expand Down Expand Up @@ -100,34 +85,21 @@ export const TextPostCard = ({ commentId }: TextPostCardProps) => {
</Flex>

{isLocked ? (
<Flex column gap='m'>
<View style={{ position: 'relative', overflow: 'hidden' }}>
<Text variant='body' size='m' style={{ opacity: 0.4 }}>
{generatePlaceholder(commentId)}
<Flex row alignItems='center' justifyContent='space-between'>
<Button
variant='secondary'
size='small'
rounded
onPress={handleUnlock}
style={{ height: 24 }}
>
{messages.unlock}
</Button>
<Flex row alignItems='center' gap='xs' onTouchEnd={handleUnlock}>
<IconLock size='s' color='default' />
<Text variant='body' size='s' strength='strong'>
{messages.membersOnly}
</Text>
<LinearGradient
colors={['transparent', color.background.white]}
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0
}}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
/>
</View>
<Flex row alignItems='center' justifyContent='space-between'>
<Button variant='secondary' size='small'>
{messages.unlock}
</Button>
<Flex row alignItems='center' gap='xs'>
<IconLock size='s' color='default' />
<Text variant='body' size='s' strength='strong'>
{messages.membersOnly}
</Text>
</Flex>
</Flex>
</Flex>
) : (
Expand Down
3 changes: 3 additions & 0 deletions packages/mobile/src/store/drawers/slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export type Drawer =
| 'PickWinners'
| 'CoinInsightsOverflowMenu'
| 'WalletRowOverflowMenu'
| 'LockedTextPost'

export type DrawerData = {
EnablePushNotifications: undefined
Expand Down Expand Up @@ -77,6 +78,7 @@ export type DrawerData = {
Comment: { userId: ID; entityId: ID; isEntityOwner: boolean; artistId: ID }
EditTrackFormOverflowMenu: undefined
PickWinners: undefined
LockedTextPost: { mint: string }
CoinInsightsOverflowMenu: { mint: string }
WalletRowOverflowMenu: {
address: string
Expand Down Expand Up @@ -117,6 +119,7 @@ const initialState: DrawersState = {
Comment: false,
EditTrackFormOverflowMenu: false,
PickWinners: false,
LockedTextPost: false,
CoinInsightsOverflowMenu: false,
WalletRowOverflowMenu: false,
data: {}
Expand Down
Loading
Loading