Skip to content

Commit

Permalink
[PAY-1197] Mobile inbox unavailable modal from profile screen (#3376)
Browse files Browse the repository at this point in the history
  • Loading branch information
dharit-tan committed May 19, 2023
1 parent ee1fae8 commit 9f675c0
Show file tree
Hide file tree
Showing 8 changed files with 374 additions and 6 deletions.
4 changes: 3 additions & 1 deletion apps/audius-client/packages/mobile/src/app/Drawers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { EnablePushNotificationsDrawer } from 'app/components/enable-push-notifi
import { FeedFilterDrawer } from 'app/components/feed-filter-drawer'
import { ForgotPasswordDrawer } from 'app/components/forgot-password-drawer'
import { GatedContentUploadPromptDrawer } from 'app/components/gated-content-upload-prompt-drawer/GatedContentUploadPromptDrawer'
import { InboxUnavailableDrawer } from 'app/components/inbox-unavailable-drawer/InboxUnavailableDrawer'
import { LockedContentDrawer } from 'app/components/locked-content-drawer'
import { OverflowMenuDrawer } from 'app/components/overflow-menu-drawer'
import { PlaybackRateDrawer } from 'app/components/playback-rate-drawer'
Expand Down Expand Up @@ -118,7 +119,8 @@ const nativeDrawersMap: { [DrawerName in Drawer]?: ComponentType } = {
GatedContentUploadPrompt: GatedContentUploadPromptDrawer,
ChatActions: ChatActionsDrawer,
BlockMessages: BlockMessagesDrawer,
SupportersInfo: SupportersInfoDrawer
SupportersInfo: SupportersInfoDrawer,
InboxUnavailable: InboxUnavailableDrawer
}

const commonDrawers = Object.entries(commonDrawersMap) as [
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
import type { ReactNode } from 'react'
import { useCallback, useMemo } from 'react'

import type { User } from '@audius/common'
import {
chatSelectors,
chatActions,
tippingActions,
cacheUsersSelectors,
ChatPermissionAction
} from '@audius/common'
import { View } from 'react-native'
import { useDispatch, useSelector } from 'react-redux'

import IconMessageLocked from 'app/assets/images/iconMessageLocked.svg'
import IconTip from 'app/assets/images/iconTip.svg'
import { Text, Button } from 'app/components/core'
import { NativeDrawer } from 'app/components/drawer'
import { useNavigation } from 'app/hooks/useNavigation'
import { getData } from 'app/store/drawers/selectors'
import { setVisibility } from 'app/store/drawers/slice'
import { makeStyles, flexRowCentered } from 'app/styles'
import { useColor } from 'app/utils/theme'

import { UserBadges } from '../user-badges'

const { unblockUser } = chatActions
const { getCanChat } = chatSelectors
const { getUser } = cacheUsersSelectors
const { beginTip } = tippingActions

const INBOX_UNAVAILABLE_MODAL_NAME = 'InboxUnavailable'

const messages = {
title: 'Inbox Unavailable',
blockee: 'You cannot send messages to users you have blocked.',
tipGated: (displayName: ReactNode) => (
<>
{'You must send '}
{displayName}
{' a tip before you can send them messages.'}
</>
),
noAction: 'You can no longer send messages to ',
info: 'This will not affect their ability to view your profile or interact with your content.',
unblockUser: 'Unblock User',
learnMore: 'Learn More',
sendAudio: 'Send $AUDIO',
cancel: 'Cancel'
}

const useStyles = makeStyles(({ spacing, typography, palette }) => ({
drawer: {
marginTop: spacing(2),
marginBottom: spacing(5),
padding: spacing(3.5),
gap: spacing(4)
},
titleContainer: {
...flexRowCentered(),
gap: spacing(3.5),
alignSelf: 'center'
},
title: {
fontSize: typography.fontSize.xl,
fontFamily: typography.fontByWeight.heavy,
color: palette.neutralLight2,
textTransform: 'uppercase',
lineHeight: typography.fontSize.xl * 1.25
},
infoContainer: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
gap: spacing(4.5),
paddingVertical: spacing(2),
paddingHorizontal: spacing(4),
backgroundColor: palette.neutralLight9,
borderWidth: 1,
borderColor: palette.neutralLight7,
borderRadius: spacing(2)
},
callToActionText: {
color: palette.neutral,
fontSize: typography.fontSize.large,
fontFamily: typography.fontByWeight.medium,
lineHeight: typography.fontSize.large * 1.3,
textAlign: 'center'
},
button: {
padding: spacing(4),
height: spacing(12)
},
buttonText: {
color: palette.neutral,
fontSize: typography.fontSize.large,
fontFamily: typography.fontByWeight.bold
},
buttonTextWhite: {
color: palette.white
},
border: {
borderBottomWidth: 1,
borderBottomColor: palette.neutralLight8
}
}))

const mapActionToContent = (
callToAction: ChatPermissionAction,
styles: ReturnType<typeof useStyles>,
user: User | null
) => {
switch (callToAction) {
case ChatPermissionAction.NONE:
return (
<>
{messages.noAction}
{user ? (
<UserBadges
user={user}
nameStyle={styles.callToActionText}
as={Text}
/>
) : null}
</>
)
case ChatPermissionAction.TIP:
return (
<>
{messages.tipGated(
user ? (
<UserBadges
user={user}
nameStyle={styles.callToActionText}
as={Text}
/>
) : null
)}
</>
)
case ChatPermissionAction.UNBLOCK:
return <>{messages.blockee}</>
default:
return null
}
}

export const InboxUnavailableDrawer = () => {
const dispatch = useDispatch()
const navigation = useNavigation()
const styles = useStyles()
const neutralLight2 = useColor('neutralLight2')

const { userId } = useSelector((state) => getData<'InboxUnavailable'>(state))
const user = useSelector((state) => getUser(state, { id: userId }))
const { callToAction } = useSelector((state) => getCanChat(state, userId))

const closeDrawer = useCallback(() => {
dispatch(
setVisibility({
drawer: 'InboxUnavailable',
visible: false
})
)
}, [dispatch])

const handleUnblockPress = useCallback(() => {
dispatch(unblockUser({ userId }))
closeDrawer()
}, [dispatch, userId, closeDrawer])

const handleLearnMorePress = useCallback(() => {
// TODO: Link to blog
closeDrawer()
}, [closeDrawer])

const handleTipPress = useCallback(() => {
dispatch(beginTip({ user, source: 'profile' }))
navigation.navigate('TipArtist')
closeDrawer()
}, [closeDrawer, dispatch, navigation, user])

const actionToButtonsMap = useMemo(() => {
return {
[ChatPermissionAction.NONE]: [
{
buttonTitle: messages.learnMore,
buttonPress: handleLearnMorePress,
buttonVariant: 'common'
}
],
[ChatPermissionAction.TIP]: [
{
buttonTitle: messages.sendAudio,
buttonPress: handleTipPress,
buttonVariant: 'primary',
buttonIcon: IconTip,
buttonTextStyle: styles.buttonTextWhite
}
],
[ChatPermissionAction.UNBLOCK]: [
{
buttonTitle: messages.unblockUser,
buttonPress: handleUnblockPress,
buttonVariant: 'primary',
buttonTextStyle: styles.buttonTextWhite
},
{
buttonTitle: messages.cancel,
buttonPress: closeDrawer,
buttonVariant: 'common'
}
]
}
}, [
handleLearnMorePress,
handleTipPress,
styles.buttonTextWhite,
handleUnblockPress,
closeDrawer
])

const content = mapActionToContent(callToAction, styles, user)

return (
<NativeDrawer drawerName={INBOX_UNAVAILABLE_MODAL_NAME}>
<View style={styles.drawer}>
<View style={styles.titleContainer}>
<IconMessageLocked fill={neutralLight2} />
<Text style={styles.title}>{messages.title}</Text>
</View>
<View style={styles.border} />
<Text style={styles.callToActionText}>{content}</Text>
{actionToButtonsMap[callToAction].map(
({
buttonTitle,
buttonPress,
buttonVariant,
buttonIcon,
buttonTextStyle
}) => (
<Button
key={buttonTitle}
title={buttonTitle}
onPress={buttonPress}
variant={buttonVariant}
icon={buttonIcon}
iconPosition='left'
styles={{
root: styles.button,
text: [styles.buttonText, buttonTextStyle]
}}
fullWidth
/>
)
)}
</View>
</NativeDrawer>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './InboxUnavailableDrawer'
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { ComponentType } from 'react'

import { useSelectTierInfo } from '@audius/common'
import type { User } from '@audius/common'
import type { ViewStyle, StyleProp, TextStyle } from 'react-native'
Expand All @@ -13,6 +15,7 @@ type UserBadgesProps = {
style?: StyleProp<ViewStyle>
nameStyle?: StyleProp<TextStyle>
hideName?: boolean
as?: ComponentType
}

const styles = StyleSheet.create({
Expand All @@ -27,12 +30,19 @@ const styles = StyleSheet.create({
})

export const UserBadges = (props: UserBadgesProps) => {
const { user, badgeSize = 14, style, nameStyle, hideName } = props
const {
user,
badgeSize = 14,
style,
nameStyle,
hideName,
as: Component = View
} = props
const { tier } = useSelectTierInfo(user.user_id)
const palette = useThemePalette()

return (
<View style={[styles.container, style]}>
<Component style={[styles.container, style]}>
{hideName ? null : (
<Text style={nameStyle} numberOfLines={1}>
{user.name}
Expand All @@ -53,7 +63,7 @@ export const UserBadges = (props: UserBadgesProps) => {
height={badgeSize + 2}
width={badgeSize + 2}
/>
</View>
</Component>
)
}

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

import type { User } from '@audius/common'
import { useDispatch } from 'react-redux'

import IconMessageLocked from 'app/assets/images/iconMessageLocked.svg'
import { Button } from 'app/components/core'
import { setVisibility } from 'app/store/drawers/slice'
import { makeStyles } from 'app/styles'

const messages = {
inboxUnavailable: 'Inbox Unavailable'
}

const useStyles = makeStyles(({ palette, spacing }) => ({
root: {
paddingHorizontal: 0,
height: spacing(8),
width: spacing(8),
marginRight: spacing(2),
borderColor: palette.neutralLight4
}
}))

type MessageLockedButtonProps = {
profile: Pick<User, 'user_id'>
}

export const MessageLockedButton = (props: MessageLockedButtonProps) => {
const styles = useStyles()
const { profile } = props
const { user_id: userId } = profile
const dispatch = useDispatch()

const handlePress = useCallback(() => {
dispatch(
setVisibility({
drawer: 'InboxUnavailable',
visible: true,
data: { userId }
})
)
}, [dispatch, userId])

return (
<Button
style={styles.root}
noText
title={messages.inboxUnavailable}
icon={IconMessageLocked}
variant={'common'}
size='small'
onPress={handlePress}
/>
)
}
Loading

0 comments on commit 9f675c0

Please sign in to comment.