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
15 changes: 12 additions & 3 deletions shared/chat/conversation/messages/message-popup/attachment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as Chat from '@/constants/chat2'
import * as React from 'react'
import type * as T from '@/constants/types'
import {type Position, fileUIName, type StylesCrossPlatform} from '@/styles'
import {useItems, useHeader} from './hooks'
import {useItems, useHeader, useModeration} from './hooks'
import * as Kb from '@/common-adapters'
import {useFSState} from '@/constants/fs'

Expand All @@ -25,7 +25,7 @@ const PopAttach = (ownProps: OwnProps) => {
const message = m?.type === 'attachment' ? m : emptyMessage
return message
})
const {downloadPath, attachmentType, id} = message
const {author, conversationIDKey, downloadPath, attachmentType, id} = message
const pending = !!message.transferState
const clearModals = C.useRouterState(s => s.dispatch.clearModals)

Expand Down Expand Up @@ -54,6 +54,9 @@ const PopAttach = (ownProps: OwnProps) => {
})
)

const {itemBlock, itemFilter, itemFlag, itemReport} = useModeration(author, conversationIDKey)
const infoPanelShowing = Chat.useChatState(s => s.infoPanelShowing)

const onJump = React.useCallback(() => {
loadMessagesCentered(id, 'always')
showInfoPanel(false, 'attachments')
Expand Down Expand Up @@ -116,7 +119,9 @@ const PopAttach = (ownProps: OwnProps) => {
: []
const itemMedia = [{icon: 'iconfont-camera', onClick: onAllMedia, title: 'All media'}] as const

const itemJump = [{icon: 'iconfont-search', onClick: onJump, title: 'Jump to message'}] as const
const itemJump = infoPanelShowing
? ([{icon: 'iconfont-search', onClick: onJump, title: 'Jump to message'}] as const)
: []

const topSection = [...itemSave, ...itemShare, ...itemDelete, ...itemExplode]

Expand All @@ -137,6 +142,10 @@ const PopAttach = (ownProps: OwnProps) => {
...itemProfile,
...itemKick,
...itemPin,
...itemBlock,
...itemFilter,
...itemReport,
...itemFlag,
]

const header = useHeader(ordinal, onHidden)
Expand Down
64 changes: 64 additions & 0 deletions shared/chat/conversation/messages/message-popup/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,70 @@ export const useItems = (ordinal: T.Chat.Ordinal, onHidden: () => void) => {
}
}

export const useModeration = (
author: string,
conversationIDKey: T.Chat.ConversationIDKey
) => {
const you = useCurrentUserState(s => s.username)
const yourMessage = author === you

const {isTeam, numPart} = Chat.useChatContext(
C.useShallow(s => {
const {teamname} = s.meta
const isTeam = !!teamname
const numPart = s.participants.all.length
return {isTeam, numPart}
})
)
const blockModalSingle = !isTeam && numPart === 2
const navigateAppend = C.useRouterState(s => s.dispatch.navigateAppend)

type BlockingModalProps = {
filterUserByDefault?: boolean
flagUserByDefault?: boolean
reportsUserByDefault?: boolean
}
const openBlockingModal = React.useCallback(
(extraProps?: BlockingModalProps) => {
navigateAppend({
props: {
blockUserByDefault: true,
context: blockModalSingle ? 'message-popup-single' : 'message-popup',
conversationIDKey,
username: author,
...extraProps,
},
selected: 'chatBlockingModal',
})
},
[blockModalSingle, conversationIDKey, navigateAppend, author]
)
const canModerate = author && !yourMessage
const onUserBlock = canModerate ? () => openBlockingModal() : undefined
const onUserFilter = C.isIOS && canModerate ? () => openBlockingModal({filterUserByDefault: true}) : undefined
const onUserReport = C.isIOS && canModerate ? () => openBlockingModal({reportsUserByDefault: true}) : undefined
const onUserFlag =
C.isIOS && canModerate
? () => openBlockingModal({flagUserByDefault: true, reportsUserByDefault: true})
: undefined

const blockTitle = isTeam ? 'Report user' : 'Block user'
const itemBlock = onUserBlock
? ([{danger: true, icon: 'iconfont-user-block', onClick: onUserBlock, title: blockTitle}] as const)
: []
const itemFilter = onUserFilter
? ([{danger: true, icon: 'iconfont-user-block', onClick: onUserFilter, title: 'Filter user'}] as const)
: []
const itemReport = !isTeam && onUserReport
? ([{danger: true, icon: 'iconfont-user-block', onClick: onUserReport, title: 'Report user'}] as const)
: []
const itemFlag = onUserFlag
? ([{danger: true, icon: 'iconfont-user-block', onClick: onUserFlag, title: 'Flag content'}] as const)
: []

return {itemBlock, itemFilter, itemFlag, itemReport}
}

export const useHeader = (ordinal: T.Chat.Ordinal, onHidden: () => void) => {
const message = Chat.useChatContext(s => {
return s.messageMap.get(ordinal) ?? emptyText
Expand Down
123 changes: 10 additions & 113 deletions shared/chat/conversation/messages/message-popup/text.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import * as C from '@/constants'
import * as Chat from '@/constants/chat2'
import {useConfigState} from '@/constants/config'
import {useCurrentUserState} from '@/constants/current-user'
import * as React from 'react'
import * as Kb from '@/common-adapters'
import * as T from '@/constants/types'
import type {Position, StylesCrossPlatform} from '@/styles'
import {useItems, useHeader} from './hooks'
import {useItems, useHeader, useModeration} from './hooks'
import openURL from '@/util/open-url'
import {useCurrentUserState} from '@/constants/current-user'

type OwnProps = {
attachTo?: React.RefObject<Kb.MeasureRef | null>
Expand All @@ -28,7 +28,6 @@ const PopText = (ownProps: OwnProps) => {
return message
})
const you = useCurrentUserState(s => s.username)
const {conversationIDKey, author} = message
const text = React.useMemo(() => {
switch (message.type) {
case 'text':
Expand Down Expand Up @@ -64,24 +63,23 @@ const PopText = (ownProps: OwnProps) => {
}
}, [message])

const {author, conversationIDKey} = message
const yourMessage = author === you
const {isTeam, messageReplyPrivately, numPart, teamType} = Chat.useChatContext(
const {messageReplyPrivately, numPart, teamType} = Chat.useChatContext(
C.useShallow(s => {
const {teamType, teamname} = s.meta
const isTeam = !!teamname
const numPart = s.participants.all.length
const {messageReplyPrivately} = s.dispatch
return {isTeam, messageReplyPrivately, numPart, teamType}
const numPart = s.participants.all.length
const {teamType} = s.meta
return {messageReplyPrivately, numPart, teamType}
})
)
// you can reply privately *if* text message, someone else's message, and not in a 1-on-1 chat
const canReplyPrivately = ['small', 'big'].includes(teamType) || numPart > 2
const navigateAppend = C.useRouterState(s => s.dispatch.navigateAppend)
const {itemBlock, itemFilter, itemFlag, itemReport} = useModeration(author, conversationIDKey)
const copyToClipboard = useConfigState(s => s.dispatch.dynamic.copyToClipboard)
const onCopy = React.useCallback(() => {
text && copyToClipboard(text)
}, [copyToClipboard, text])

// you can reply privately *if* text message, someone else's message, and not in a 1-on-1 chat
const canReplyPrivately = teamType === 'small' || teamType === 'big' || numPart > 2
const _onReplyPrivately = React.useCallback(() => {
messageReplyPrivately(ordinal)
}, [messageReplyPrivately, ordinal])
Expand All @@ -90,63 +88,6 @@ const PopText = (ownProps: OwnProps) => {
// don't pass onViewMap if we don't have a coordinate (e.g. when a location share ends)
const onViewMap =
mapUnfurl?.mapInfo && !mapUnfurl.mapInfo.isLiveLocationDone ? () => openURL(mapUnfurl.url) : undefined
const blockModalSingle = !isTeam && numPart === 2

const _onUserReport = React.useCallback(() => {
navigateAppend({
props: {
blockUserByDefault: true,
context: blockModalSingle ? 'message-popup-single' : 'message-popup',
conversationIDKey,
reportsUserByDefault: true,
username: author,
},
selected: 'chatBlockingModal',
})
}, [conversationIDKey, blockModalSingle, navigateAppend, author])
const onUserReport = C.isIOS && author && !yourMessage ? () => _onUserReport : undefined

const _onUserFlag = React.useCallback(() => {
navigateAppend({
props: {
blockUserByDefault: true,
context: blockModalSingle ? 'message-popup-single' : 'message-popup',
conversationIDKey,
flagUserByDefault: true,
reportsUserByDefault: true,
username: author,
},
selected: 'chatBlockingModal',
})
}, [conversationIDKey, blockModalSingle, navigateAppend, author])
const onUserFlag = C.isIOS && author && !yourMessage ? _onUserFlag : undefined

const _onUserBlock = React.useCallback(() => {
navigateAppend({
props: {
blockUserByDefault: true,
context: blockModalSingle ? 'message-popup-single' : 'message-popup',
conversationIDKey,
username: author,
},
selected: 'chatBlockingModal',
})
}, [conversationIDKey, blockModalSingle, navigateAppend, author])
const onUserBlock = author && !yourMessage ? _onUserBlock : undefined

const _onUserFilter = React.useCallback(() => {
navigateAppend({
props: {
blockUserByDefault: true,
context: blockModalSingle ? 'message-popup-single' : 'message-popup',
conversationIDKey,
filterUserByDefault: true,
username: author,
},
selected: 'chatBlockingModal',
})
}, [conversationIDKey, blockModalSingle, navigateAppend, author])
const onUserFilter = C.isIOS && author && !yourMessage ? () => _onUserFilter : undefined

const i = useItems(ordinal, onHidden)
const {itemReaction, itemBot, itemCopyLink, itemReply, itemEdit, itemForward, itemPin, itemUnread} = i
Expand All @@ -162,50 +103,6 @@ const PopText = (ownProps: OwnProps) => {
? ([{icon: 'iconfont-reply', onClick: onReplyPrivately, title: 'Reply privately'}] as const)
: []

const itemBlock = !yourMessage
? ([
{
danger: true,
icon: 'iconfont-user-block',
onClick: onUserBlock,
title: isTeam ? 'Report user' : 'Block user',
},
] as const)
: []
const itemFilter =
!yourMessage && onUserFilter
? ([
{
danger: true,
icon: 'iconfont-user-block',
onClick: onUserFilter,
title: 'Filter user',
},
] as const)
: []
const itemReport =
!yourMessage && !isTeam && onUserReport
? ([
{
danger: true,
icon: 'iconfont-user-block',
onClick: onUserReport,
title: 'Report user',
},
] as const)
: []
const itemFlag =
!yourMessage && onUserFlag
? ([
{
danger: true,
icon: 'iconfont-user-block',
onClick: onUserFlag,
title: 'Flag content',
},
] as const)
: []

const items = [
...itemReaction,
...itemEdit,
Expand Down