Skip to content
This repository has been archived by the owner on Oct 4, 2023. It is now read-only.

[PAY-1516] Chat report abuse flow #3636

Merged
merged 3 commits into from
Jun 22, 2023
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
19 changes: 19 additions & 0 deletions packages/common/src/store/pages/chat/sagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ const {
fetchBlockersSucceeded,
unblockUser,
blockUser,
reportUser,
fetchPermissions,
fetchPermissionsSucceeded,
fetchLinkUnfurl,
Expand Down Expand Up @@ -517,6 +518,19 @@ function* doUnblockUser(action: ReturnType<typeof unblockUser>) {
}
}

function* doReportUser(action: ReturnType<typeof reportUser>) {
dharit-tan marked this conversation as resolved.
Show resolved Hide resolved
try {
console.log('reportUser', action.payload)
} catch (e) {
console.error('reportUserFailed', e)
const reportToSentry = yield* getContext('reportToSentry')
reportToSentry({
level: ErrorLevel.Error,
error: e as Error
})
}
}

function* doFetchPermissions(action: ReturnType<typeof fetchPermissions>) {
try {
const currentUserId = yield* select(getUserId)
Expand Down Expand Up @@ -667,6 +681,10 @@ function* watchUnblockUser() {
yield takeEvery(unblockUser, doUnblockUser)
}

function* watchReportUser() {
yield takeEvery(reportUser, doReportUser)
}

function* watchFetchPermissions() {
yield takeEvery(fetchPermissions, doFetchPermissions)
}
Expand Down Expand Up @@ -694,6 +712,7 @@ export const sagas = () => {
watchFetchBlockers,
watchBlockUser,
watchUnblockUser,
watchReportUser,
watchFetchPermissions,
watchFetchLinkUnfurlMetadata,
watchDeleteChat
Expand Down
3 changes: 3 additions & 0 deletions packages/common/src/store/pages/chat/slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,9 @@ const slice = createSlice({
unblockUser: (_state, _action: PayloadAction<{ userId: ID }>) => {
// triggers saga
},
reportUser: (_state, _action: PayloadAction<{ userId: ID }>) => {
// triggers saga
},
fetchPermissions: (_state, _action: PayloadAction<{ userIds: ID[] }>) => {
// triggers saga
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,20 @@ import { useColor } from 'app/utils/theme'

const { getUser } = cacheUsersSelectors
const { getDoesBlockUser, getCanCreateChat } = chatSelectors
const { blockUser, unblockUser, createChat } = chatActions
const { blockUser, unblockUser, createChat, reportUser } = chatActions

const BLOCK_MESSAGES_MODAL_NAME = 'BlockMessages'

const messages = {
title: 'Are you sure?',
confirmBlock: (userName?: string) => (
confirmBlock: (userName?: string, isReportAbuse?: boolean) => (
<>
{'Are you sure you want to block '}
{'Are you sure you want to '}
{isReportAbuse ? 'report ' : 'block '}
{userName}
{' from sending messages to your inbox? '}
{isReportAbuse
? ' for abuse? They will be blocked from sending you new messages.'
: ' from sending messages to your inbox?'}
</>
),
confirmUnblock: (userName?: string) => (
Expand All @@ -39,6 +42,7 @@ const messages = {
info: 'This will not affect their ability to view your profile or interact with your content.',
blockUser: 'Block User',
unblockUser: 'Unblock User',
reportUser: 'Report & Block',
cancel: 'Cancel'
}

Expand Down Expand Up @@ -106,7 +110,7 @@ export const BlockMessagesDrawer = () => {
const neutral = useColor('neutral')
const dispatch = useDispatch()
const { data } = useDrawer('BlockMessages')
const { userId, shouldOpenChat } = data
const { userId, shouldOpenChat, isReportAbuse } = data
const user = useSelector((state) => getUser(state, { id: userId }))
// Assuming blockees have already been fetched in ProfileActionsDrawer.
const doesBlockUser = useSelector((state) => getDoesBlockUser(state, userId))
Expand All @@ -122,14 +126,24 @@ export const BlockMessagesDrawer = () => {
}
} else {
dispatch(blockUser({ userId }))
if (isReportAbuse) {
dispatch(reportUser({ userId }))
}
}
dispatch(
setVisibility({
drawer: 'BlockMessages',
visible: false
})
)
}, [canCreateChat, dispatch, doesBlockUser, shouldOpenChat, userId])
}, [
canCreateChat,
dispatch,
doesBlockUser,
isReportAbuse,
shouldOpenChat,
userId
])

const handleCancelPress = useCallback(() => {
dispatch(
Expand All @@ -150,7 +164,7 @@ export const BlockMessagesDrawer = () => {
<Text style={styles.confirm}>
{doesBlockUser
? messages.confirmUnblock(user?.name)
: messages.confirmBlock(user?.name)}
: messages.confirmBlock(user?.name, isReportAbuse)}
</Text>
{doesBlockUser ? null : (
<View style={styles.infoContainer}>
Expand All @@ -164,7 +178,13 @@ export const BlockMessagesDrawer = () => {
</View>
)}
<Button
title={doesBlockUser ? messages.unblockUser : messages.blockUser}
title={
isReportAbuse
? messages.reportUser
: doesBlockUser
? messages.unblockUser
: messages.blockUser
}
onPress={handleConfirmPress}
variant={doesBlockUser ? 'primary' : 'destructive'}
styles={{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const messages = {
visitProfile: 'Visit Profile',
blockMessages: 'Block Messages',
unblockMessages: 'Unblock Messages',
reportAbuse: 'Report Abuse',
deleteConversation: 'Delete Conversation'
}

Expand Down Expand Up @@ -81,6 +82,17 @@ export const ChatActionsDrawer = () => {
)
}, [closeDrawer, dispatch, userId])

const handleReportPress = useCallback(() => {
closeDrawer()
dispatch(
setVisibility({
drawer: 'BlockMessages',
visible: true,
data: { userId, isReportAbuse: true }
})
)
}, [closeDrawer, dispatch, userId])

const handleDeletePress = useCallback(() => {
closeDrawer()
dispatch(
Expand Down Expand Up @@ -109,6 +121,11 @@ export const ChatActionsDrawer = () => {
</Text>
</TouchableOpacity>
</View>
<View style={styles.row}>
<TouchableOpacity onPress={handleReportPress}>
<Text style={styles.text}>{messages.reportAbuse}</Text>
</TouchableOpacity>
</View>
<View style={styles.row}>
<TouchableOpacity onPress={handleDeletePress}>
<Text style={[styles.text, styles.deleteText]}>
Expand Down
6 changes: 5 additions & 1 deletion packages/mobile/src/store/drawers/slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,11 @@ export type DrawerData = {
ChatActions: { userId: number; chatId: string }
CreateChatActions: { userId: number }
ProfileActions: undefined
BlockMessages: { userId: number; shouldOpenChat: boolean }
BlockMessages: {
userId: number
shouldOpenChat: boolean
isReportAbuse: boolean
}
DeleteChat: { chatId: string }
SupportersInfo: undefined
InboxUnavailable: { userId: number; shouldOpenChat: boolean }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,20 @@ import { UserNameAndBadges } from 'components/user-name-and-badges/UserNameAndBa

import styles from './BlockUserConfirmationModal.module.css'

const { blockUser } = chatActions
const { blockUser, reportUser } = chatActions

const messages = {
title: 'Are you sure?',
confirm: 'Block User',
confirmBlock: 'Block User',
confirmReport: 'Report & Block',
cancel: 'Cancel',
content: (user: User) => (
content: (user: User, isReport?: boolean) => (
<>
Are you sure you want to block <UserNameAndBadges user={user} /> from
sending messages to your inbox?
Are you sure you want to {isReport ? 'report' : 'block'}{' '}
<UserNameAndBadges user={user} />{' '}
{isReport
? 'for abuse? They will be blocked from sending you new messages.'
: 'from sending messages to your inbox?'}
</>
),
callout:
Expand All @@ -39,18 +43,23 @@ type BlockUserConfirmationModalProps = {
isVisible: boolean
onClose: () => void
user: User
isReportAbuse?: boolean
}

export const BlockUserConfirmationModal = ({
isVisible,
onClose,
user
user,
isReportAbuse
}: BlockUserConfirmationModalProps) => {
const dispatch = useDispatch()
const handleConfirmClicked = useCallback(() => {
dispatch(blockUser({ userId: user.user_id }))
if (isReportAbuse) {
dispatch(reportUser({ userId: user.user_id }))
}
onClose()
}, [dispatch, onClose, user])
}, [dispatch, isReportAbuse, onClose, user.user_id])

return (
<Modal bodyClassName={styles.root} isOpen={isVisible} onClose={onClose}>
Expand All @@ -62,7 +71,7 @@ export const BlockUserConfirmationModal = ({
/>
</ModalHeader>
<ModalContent className={styles.content}>
<div>{messages.content(user)}</div>
<div>{messages.content(user, isReportAbuse)}</div>
<HelpCallout icon={<IconInfo />} content={messages.callout} />
</ModalContent>
<ModalFooter className={styles.footer}>
Expand All @@ -75,7 +84,7 @@ export const BlockUserConfirmationModal = ({
<Button
className={styles.button}
type={ButtonType.DESTRUCTIVE}
text={messages.confirm}
text={isReportAbuse ? messages.confirmReport : messages.confirmBlock}
onClick={handleConfirmClicked}
/>
</ModalFooter>
Expand Down
39 changes: 29 additions & 10 deletions packages/web/src/pages/chat-page/components/ChatHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
IconBlockMessages,
IconUnblockMessages,
IconUser,
IconTrash
IconTrash,
IconError
} from '@audius/stems'
import { push as pushRoute } from 'connected-react-router'
import { useDispatch, useSelector } from 'react-redux'
Expand All @@ -32,6 +33,7 @@ const messages = {
chatSettings: 'Chat Settings',
block: 'Block Messages',
unblock: 'Unblock Messages',
report: 'Report Abuse',
delete: 'Delete Conversation',
visit: "Visit User's Profile"
}
Expand All @@ -57,6 +59,7 @@ export const ChatHeader = forwardRef<HTMLDivElement, ChatHeaderProps>(
useState(false)
const [isBlockUserModalVisible, setIsBlockUserModalVisible] =
useState(false)
const [isReportAbuse, setIsReportAbuse] = useState(false)
const [isDeleteChatModalVisible, setIsDeleteChatModalVisible] =
useState(false)
const users = useProxySelector(
Expand All @@ -83,6 +86,16 @@ export const ChatHeader = forwardRef<HTMLDivElement, ChatHeaderProps>(
setIsBlockUserModalVisible(true)
}, [setIsBlockUserModalVisible])

const handleReportClicked = useCallback(() => {
setIsReportAbuse(true)
setIsBlockUserModalVisible(true)
}, [setIsReportAbuse])

const handleCloseBlockModal = useCallback(() => {
setIsReportAbuse(false)
setIsBlockUserModalVisible(false)
}, [setIsReportAbuse])

const handleVisitClicked = useCallback(() => {
dispatch(pushRoute(profilePage(user.handle)))
}, [dispatch, user])
Expand All @@ -92,6 +105,16 @@ export const ChatHeader = forwardRef<HTMLDivElement, ChatHeaderProps>(
}, [setIsDeleteChatModalVisible])

const overflowItems = [
{
text: messages.delete,
dharit-tan marked this conversation as resolved.
Show resolved Hide resolved
icon: <IconTrash />,
onClick: handleDeleteClicked
},
{
text: messages.visit,
icon: <IconUser />,
onClick: handleVisitClicked
},
isBlocked
? {
text: messages.unblock,
Expand All @@ -104,14 +127,9 @@ export const ChatHeader = forwardRef<HTMLDivElement, ChatHeaderProps>(
onClick: handleBlockClicked
},
{
text: messages.delete,
icon: <IconTrash />,
onClick: handleDeleteClicked
},
{
text: messages.visit,
icon: <IconUser />,
onClick: handleVisitClicked
text: messages.report,
icon: <IconError />,
onClick: handleReportClicked
}
]

Expand Down Expand Up @@ -164,7 +182,8 @@ export const ChatHeader = forwardRef<HTMLDivElement, ChatHeaderProps>(
<BlockUserConfirmationModal
user={user}
isVisible={isBlockUserModalVisible}
onClose={() => setIsBlockUserModalVisible(false)}
onClose={handleCloseBlockModal}
isReportAbuse={isReportAbuse}
/>
<DeleteChatConfirmationModal
chatId={currentChatId}
Expand Down