about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorSamuel Newman <mozzius@protonmail.com>2025-01-10 23:35:21 +0000
committerGitHub <noreply@github.com>2025-01-10 23:35:21 +0000
commitd7f5ee8415bd6d37a889d395f30b912cb1068e09 (patch)
tree577afe4b7955a9753e7d321d26aa7cf43720b1cf /src
parent42a44682650598404368ea9d5c734d49bfdbd812 (diff)
downloadvoidsky-d7f5ee8415bd6d37a889d395f30b912cb1068e09.tar.zst
Conversation-level reporting by reporting most recent message available (#7423)
* report latest message via convo menu

* check all messages we have

* fix types

* rm convo warning
Diffstat (limited to 'src')
-rw-r--r--src/components/ReportDialog/SelectReportOptionView.tsx4
-rw-r--r--src/components/dms/ConvoMenu.tsx17
-rw-r--r--src/components/dms/MessagesListHeader.tsx10
-rw-r--r--src/screens/Messages/components/ChatListItem.tsx111
4 files changed, 88 insertions, 54 deletions
diff --git a/src/components/ReportDialog/SelectReportOptionView.tsx b/src/components/ReportDialog/SelectReportOptionView.tsx
index 169c07d73..92a442cbd 100644
--- a/src/components/ReportDialog/SelectReportOptionView.tsx
+++ b/src/components/ReportDialog/SelectReportOptionView.tsx
@@ -25,9 +25,7 @@ import {SquareArrowTopRight_Stroke2_Corner0_Rounded as SquareArrowTopRight} from
 import {Text} from '#/components/Typography'
 import {ReportDialogProps} from './types'
 
-export function SelectReportOptionView({
-  ...props
-}: {
+export function SelectReportOptionView(props: {
   params: ReportDialogProps['params']
   labelers: AppBskyLabelerDefs.LabelerViewDetailed[]
   onSelectReportOption: (reportOption: ReportOption) => void
diff --git a/src/components/dms/ConvoMenu.tsx b/src/components/dms/ConvoMenu.tsx
index e1f8df10b..ba1d4ee54 100644
--- a/src/components/dms/ConvoMenu.tsx
+++ b/src/components/dms/ConvoMenu.tsx
@@ -35,6 +35,7 @@ import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute} from '#/components/
 import * as Menu from '#/components/Menu'
 import * as Prompt from '#/components/Prompt'
 import {Bubble_Stroke2_Corner2_Rounded as Bubble} from '../icons/Bubble'
+import {ReportDialog} from './ReportDialog'
 
 let ConvoMenu = ({
   convo: initialConvo,
@@ -44,6 +45,7 @@ let ConvoMenu = ({
   showMarkAsRead,
   hideTrigger,
   blockInfo,
+  latestReportableMessage,
   style,
 }: {
   convo: ChatBskyConvoDefs.ConvoView
@@ -56,6 +58,7 @@ let ConvoMenu = ({
     listBlocks: ModerationCause[]
     userBlock?: ModerationCause
   }
+  latestReportableMessage?: ChatBskyConvoDefs.MessageView
   style?: ViewStyleProp['style']
 }): React.ReactNode => {
   const navigation = useNavigation<NavigationProp>()
@@ -222,7 +225,19 @@ let ConvoMenu = ({
         convoId={convo.id}
         currentScreen={currentScreen}
       />
-      <ReportConversationPrompt control={reportControl} />
+      {latestReportableMessage ? (
+        <ReportDialog
+          params={{
+            type: 'convoMessage',
+            convoId: convo.id,
+            message: latestReportableMessage,
+          }}
+          control={reportControl}
+        />
+      ) : (
+        <ReportConversationPrompt control={reportControl} />
+      )}
+
       <BlockedByListDialog
         control={blockedByListControl}
         listBlocks={listBlocks}
diff --git a/src/components/dms/MessagesListHeader.tsx b/src/components/dms/MessagesListHeader.tsx
index acffa0c2b..6ac64a712 100644
--- a/src/components/dms/MessagesListHeader.tsx
+++ b/src/components/dms/MessagesListHeader.tsx
@@ -151,6 +151,15 @@ function HeaderReady({
         moderation.ui('displayName'),
       )
 
+  const latestMessageFromOther = convoState.items.findLast(
+    item => item.type === 'message' && item.message.sender.did === profile.did,
+  )
+
+  const latestReportableMessage =
+    latestMessageFromOther?.type === 'message'
+      ? latestMessageFromOther.message
+      : undefined
+
   return (
     <View style={[a.flex_1]}>
       <View style={[a.w_full, a.flex_row, a.align_center, a.justify_between]}>
@@ -208,6 +217,7 @@ function HeaderReady({
             profile={profile}
             currentScreen="conversation"
             blockInfo={blockInfo}
+            latestReportableMessage={latestReportableMessage}
           />
         )}
       </View>
diff --git a/src/screens/Messages/components/ChatListItem.tsx b/src/screens/Messages/components/ChatListItem.tsx
index 6b8deea30..11aada71b 100644
--- a/src/screens/Messages/components/ChatListItem.tsx
+++ b/src/screens/Messages/components/ChatListItem.tsx
@@ -112,64 +112,74 @@ function ChatListItemReady({
 
   const isDimStyle = convo.muted || moderation.blocked || isDeletedAccount
 
-  const {lastMessage, lastMessageSentAt} = useMemo(() => {
-    let lastMessage = _(msg`No messages yet`)
-    let lastMessageSentAt: string | null = null
-
-    if (ChatBskyConvoDefs.isMessageView(convo.lastMessage)) {
-      const isFromMe = convo.lastMessage.sender?.did === currentAccount?.did
-
-      if (convo.lastMessage.text) {
-        if (isFromMe) {
-          lastMessage = _(msg`You: ${convo.lastMessage.text}`)
-        } else {
-          lastMessage = convo.lastMessage.text
+  const {lastMessage, lastMessageSentAt, latestReportableMessage} =
+    useMemo(() => {
+      // eslint-disable-next-line @typescript-eslint/no-shadow
+      let lastMessage = _(msg`No messages yet`)
+      // eslint-disable-next-line @typescript-eslint/no-shadow
+      let lastMessageSentAt: string | null = null
+      // eslint-disable-next-line @typescript-eslint/no-shadow
+      let latestReportableMessage: ChatBskyConvoDefs.MessageView | undefined
+
+      if (ChatBskyConvoDefs.isMessageView(convo.lastMessage)) {
+        const isFromMe = convo.lastMessage.sender?.did === currentAccount?.did
+
+        if (!isFromMe) {
+          latestReportableMessage = convo.lastMessage
         }
-      } else if (convo.lastMessage.embed) {
-        const defaultEmbeddedContentMessage = _(
-          msg`(contains embedded content)`,
-        )
-
-        if (AppBskyEmbedRecord.isView(convo.lastMessage.embed)) {
-          const embed = convo.lastMessage.embed
-
-          if (AppBskyEmbedRecord.isViewRecord(embed.record)) {
-            const record = embed.record
-            const path = postUriToRelativePath(record.uri, {
-              handle: record.author.handle,
-            })
-            const href = path ? toBskyAppUrl(path) : undefined
-            const short = href
-              ? toShortUrl(href)
-              : defaultEmbeddedContentMessage
+
+        if (convo.lastMessage.text) {
+          if (isFromMe) {
+            lastMessage = _(msg`You: ${convo.lastMessage.text}`)
+          } else {
+            lastMessage = convo.lastMessage.text
+          }
+        } else if (convo.lastMessage.embed) {
+          const defaultEmbeddedContentMessage = _(
+            msg`(contains embedded content)`,
+          )
+
+          if (AppBskyEmbedRecord.isView(convo.lastMessage.embed)) {
+            const embed = convo.lastMessage.embed
+
+            if (AppBskyEmbedRecord.isViewRecord(embed.record)) {
+              const record = embed.record
+              const path = postUriToRelativePath(record.uri, {
+                handle: record.author.handle,
+              })
+              const href = path ? toBskyAppUrl(path) : undefined
+              const short = href
+                ? toShortUrl(href)
+                : defaultEmbeddedContentMessage
+              if (isFromMe) {
+                lastMessage = _(msg`You: ${short}`)
+              } else {
+                lastMessage = short
+              }
+            }
+          } else {
             if (isFromMe) {
-              lastMessage = _(msg`You: ${short}`)
+              lastMessage = _(msg`You: ${defaultEmbeddedContentMessage}`)
             } else {
-              lastMessage = short
+              lastMessage = defaultEmbeddedContentMessage
             }
           }
-        } else {
-          if (isFromMe) {
-            lastMessage = _(msg`You: ${defaultEmbeddedContentMessage}`)
-          } else {
-            lastMessage = defaultEmbeddedContentMessage
-          }
         }
-      }
 
-      lastMessageSentAt = convo.lastMessage.sentAt
-    }
-    if (ChatBskyConvoDefs.isDeletedMessageView(convo.lastMessage)) {
-      lastMessage = isDeletedAccount
-        ? _(msg`Conversation deleted`)
-        : _(msg`Message deleted`)
-    }
+        lastMessageSentAt = convo.lastMessage.sentAt
+      }
+      if (ChatBskyConvoDefs.isDeletedMessageView(convo.lastMessage)) {
+        lastMessage = isDeletedAccount
+          ? _(msg`Conversation deleted`)
+          : _(msg`Message deleted`)
+      }
 
-    return {
-      lastMessage,
-      lastMessageSentAt,
-    }
-  }, [_, convo.lastMessage, currentAccount?.did, isDeletedAccount])
+      return {
+        lastMessage,
+        lastMessageSentAt,
+        latestReportableMessage,
+      }
+    }, [_, convo.lastMessage, currentAccount?.did, isDeletedAccount])
 
   const [showActions, setShowActions] = useState(false)
 
@@ -412,6 +422,7 @@ function ChatListItemReady({
               opacity: !gtMobile || showActions || menuControl.isOpen ? 1 : 0,
             },
           ]}
+          latestReportableMessage={latestReportableMessage}
         />
         <LeaveConvoPrompt
           control={leaveConvoControl}