about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/screens/Messages/Conversation/MessageListError.tsx58
-rw-r--r--src/screens/Messages/Conversation/MessagesList.tsx24
-rw-r--r--src/state/messages/convo/agent.ts70
-rw-r--r--src/state/messages/convo/types.ts22
4 files changed, 96 insertions, 78 deletions
diff --git a/src/screens/Messages/Conversation/MessageListError.tsx b/src/screens/Messages/Conversation/MessageListError.tsx
index 5f5df4fc9..38a63b0f1 100644
--- a/src/screens/Messages/Conversation/MessageListError.tsx
+++ b/src/screens/Messages/Conversation/MessageListError.tsx
@@ -5,8 +5,9 @@ import {useLingui} from '@lingui/react'
 
 import {ConvoItem, ConvoItemError} from '#/state/messages/convo/types'
 import {atoms as a, useTheme} from '#/alf'
+import {Button, ButtonIcon, ButtonText} from '#/components/Button'
+import {ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded as Refresh} from '#/components/icons/ArrowRotateCounterClockwise'
 import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
-import {InlineLinkText} from '#/components/Link'
 import {Text} from '#/components/Typography'
 
 export function MessageListError({
@@ -21,39 +22,52 @@ export function MessageListError({
       [ConvoItemError.Network]: _(
         msg`There was an issue connecting to the chat.`,
       ),
-      [ConvoItemError.HistoryFailed]: _(msg`Failed to load past messages.`),
-      [ConvoItemError.PollFailed]: _(
+      [ConvoItemError.FirehoseFailed]: _(
         msg`This chat was disconnected due to a network error.`,
       ),
+      [ConvoItemError.HistoryFailed]: _(msg`Failed to load past messages.`),
+      [ConvoItemError.PendingFailed]: _(msg`Failed to send message(s).`),
     }[item.code]
   }, [_, item.code])
 
   return (
-    <View style={[a.py_md, a.align_center]}>
+    <View style={[a.py_lg, a.align_center]}>
       <View
         style={[
+          a.flex_row,
           a.align_center,
-          a.pt_md,
-          a.pb_lg,
-          a.px_3xl,
+          a.justify_between,
+          a.gap_lg,
+          a.py_md,
+          a.px_lg,
           a.rounded_md,
           t.atoms.bg_contrast_25,
-          {maxWidth: 300},
+          {maxWidth: 400},
         ]}>
-        <CircleInfo size="lg" fill={t.palette.negative_400} />
-        <Text style={[a.pt_sm, a.leading_snug]}>
-          {message}{' '}
-          <InlineLinkText
-            to="#"
-            label={_(msg`Press to retry`)}
-            onPress={e => {
-              e.preventDefault()
-              item.retry()
-              return false
-            }}>
-            {_(msg`Retry.`)}
-          </InlineLinkText>
-        </Text>
+        <View style={[a.flex_row, a.align_start, a.justify_between, a.gap_sm]}>
+          <CircleInfo
+            size="sm"
+            fill={t.palette.negative_400}
+            style={[{top: 3}]}
+          />
+          <View style={[a.flex_1, {maxWidth: 200}]}>
+            <Text style={[a.leading_snug]}>{message}</Text>
+          </View>
+        </View>
+
+        <Button
+          label={_(msg`Press to retry`)}
+          size="small"
+          variant="ghost"
+          color="secondary"
+          onPress={e => {
+            e.preventDefault()
+            item.retry()
+            return false
+          }}>
+          <ButtonText>{_(msg`Retry`)}</ButtonText>
+          <ButtonIcon icon={Refresh} position="right" />
+        </Button>
       </View>
     </View>
   )
diff --git a/src/screens/Messages/Conversation/MessagesList.tsx b/src/screens/Messages/Conversation/MessagesList.tsx
index 0b8ab5249..f99a41b7f 100644
--- a/src/screens/Messages/Conversation/MessagesList.tsx
+++ b/src/screens/Messages/Conversation/MessagesList.tsx
@@ -8,8 +8,6 @@ import {runOnJS, useSharedValue} from 'react-native-reanimated'
 import {ReanimatedScrollEvent} from 'react-native-reanimated/lib/typescript/reanimated2/hook/commonTypes'
 import {useSafeAreaInsets} from 'react-native-safe-area-context'
 import {AppBskyRichtextFacet, RichText} from '@atproto/api'
-import {msg, Trans} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
 
 import {shortenLinks} from '#/lib/strings/rich-text-manip'
 import {isIOS} from '#/platform/detection'
@@ -22,7 +20,6 @@ import {List} from 'view/com/util/List'
 import {MessageInput} from '#/screens/Messages/Conversation/MessageInput'
 import {MessageListError} from '#/screens/Messages/Conversation/MessageListError'
 import {atoms as a, useBreakpoints} from '#/alf'
-import {Button, ButtonText} from '#/components/Button'
 import {MessageItem} from '#/components/dms/MessageItem'
 import {Loader} from '#/components/Loader'
 import {Text} from '#/components/Typography'
@@ -41,25 +38,6 @@ function MaybeLoader({isLoading}: {isLoading: boolean}) {
   )
 }
 
-function RetryButton({onPress}: {onPress: () => unknown}) {
-  const {_} = useLingui()
-
-  return (
-    <View style={{alignItems: 'center'}}>
-      <Button
-        label={_(msg`Press to Retry`)}
-        onPress={onPress}
-        variant="ghost"
-        color="negative"
-        size="small">
-        <ButtonText>
-          <Trans>Press to Retry</Trans>
-        </ButtonText>
-      </Button>
-    </View>
-  )
-}
-
 function renderItem({item}: {item: ConvoItem}) {
   if (item.type === 'message' || item.type === 'pending-message') {
     return (
@@ -71,8 +49,6 @@ function renderItem({item}: {item: ConvoItem}) {
     )
   } else if (item.type === 'deleted-message') {
     return <Text>Deleted message</Text>
-  } else if (item.type === 'pending-retry') {
-    return <RetryButton onPress={item.retry} />
   } else if (item.type === 'error-recoverable') {
     return <MessageListError item={item} />
   }
diff --git a/src/state/messages/convo/agent.ts b/src/state/messages/convo/agent.ts
index 25e138fb7..12e24577e 100644
--- a/src/state/messages/convo/agent.ts
+++ b/src/state/messages/convo/agent.ts
@@ -401,7 +401,7 @@ export class Convo {
       // throw new Error('UNCOMMENT TO TEST INIT FAILURE')
       this.dispatch({event: ConvoDispatchEvent.Ready})
     } catch (e: any) {
-      logger.error('Convo: setup() failed')
+      logger.error(e, {context: 'Convo: setup failed'})
 
       this.dispatch({
         event: ConvoDispatchEvent.Error,
@@ -413,6 +413,7 @@ export class Convo {
           },
         },
       })
+      this.commit()
     }
   }
 
@@ -500,7 +501,7 @@ export class Convo {
       this.sender = sender || this.sender
       this.recipients = recipients || this.recipients
     } catch (e: any) {
-      logger.error(`Convo: failed to refresh convo`)
+      logger.error(e, {context: `Convo: failed to refresh convo`})
 
       this.footerItems.set(ConvoItemError.Network, {
         type: 'error-recoverable',
@@ -601,17 +602,17 @@ export class Convo {
   }
 
   onFirehoseConnect() {
-    this.footerItems.delete(ConvoItemError.PollFailed)
+    this.footerItems.delete(ConvoItemError.FirehoseFailed)
     this.commit()
   }
 
   onFirehoseError(error?: MessagesEventBusError) {
-    this.footerItems.set(ConvoItemError.PollFailed, {
+    this.footerItems.set(ConvoItemError.FirehoseFailed, {
       type: 'error-recoverable',
-      key: ConvoItemError.PollFailed,
-      code: ConvoItemError.PollFailed,
+      key: ConvoItemError.FirehoseFailed,
+      code: ConvoItemError.FirehoseFailed,
       retry: () => {
-        this.footerItems.delete(ConvoItemError.PollFailed)
+        this.footerItems.delete(ConvoItemError.FirehoseFailed)
         this.commit()
         error?.retry()
       },
@@ -772,13 +773,21 @@ export class Convo {
       await this.processPendingMessages()
 
       this.commit()
-    } catch (e) {
-      this.footerItems.set('pending-retry', {
-        type: 'pending-retry',
-        key: 'pending-retry',
-        retry: this.batchRetryPendingMessages.bind(this),
+    } catch (e: any) {
+      logger.error(e, {context: `Convo: failed to send message`})
+      this.footerItems.set(ConvoItemError.PendingFailed, {
+        type: 'error-recoverable',
+        key: ConvoItemError.PendingFailed,
+        code: ConvoItemError.PendingFailed,
+        retry: () => {
+          this.footerItems.delete(ConvoItemError.PendingFailed)
+          this.commit()
+          this.batchRetryPendingMessages()
+        },
       })
       this.commit()
+    } finally {
+      this.isProcessingPendingMessages = false
     }
   }
 
@@ -789,10 +798,8 @@ export class Convo {
       logger.DebugContext.convo,
     )
 
-    this.footerItems.delete('pending-retry')
-    this.commit()
-
     try {
+      // throw new Error('UNCOMMENT TO TEST RETRY')
       const messageArray = Array.from(this.pendingMessages.values())
       const {data} = await networkRetry(2, () => {
         return this.agent.api.chat.bsky.convo.sendMessageBatch(
@@ -831,11 +838,23 @@ export class Convo {
       }
 
       this.commit()
-    } catch (e) {
-      this.footerItems.set('pending-retry', {
-        type: 'pending-retry',
-        key: 'pending-retry',
-        retry: this.batchRetryPendingMessages.bind(this),
+
+      logger.debug(
+        `Convo: sent ${this.pendingMessages.size} pending messages`,
+        {},
+        logger.DebugContext.convo,
+      )
+    } catch (e: any) {
+      logger.error(e, {context: `Convo: failed to batch retry messages`})
+      this.footerItems.set(ConvoItemError.PendingFailed, {
+        type: 'error-recoverable',
+        key: ConvoItemError.PendingFailed,
+        code: ConvoItemError.PendingFailed,
+        retry: () => {
+          this.footerItems.delete(ConvoItemError.PendingFailed)
+          this.commit()
+          this.batchRetryPendingMessages()
+        },
       })
       this.commit()
     }
@@ -862,7 +881,8 @@ export class Convo {
           },
         )
       })
-    } catch (e) {
+    } catch (e: any) {
+      logger.error(e, {context: `Convo: failed to delete message`})
       this.deletedMessages.delete(messageId)
       this.commit()
       throw e
@@ -875,10 +895,6 @@ export class Convo {
   getItems(): ConvoItem[] {
     const items: ConvoItem[] = []
 
-    this.headerItems.forEach(item => {
-      items.push(item)
-    })
-
     this.pastMessages.forEach(m => {
       if (ChatBskyConvoDefs.isMessageView(m)) {
         items.unshift({
@@ -897,6 +913,10 @@ export class Convo {
       }
     })
 
+    this.headerItems.forEach(item => {
+      items.unshift(item)
+    })
+
     this.newMessages.forEach(m => {
       if (ChatBskyConvoDefs.isMessageView(m)) {
         items.push({
diff --git a/src/state/messages/convo/types.ts b/src/state/messages/convo/types.ts
index 2ed2eeaff..920635c8c 100644
--- a/src/state/messages/convo/types.ts
+++ b/src/state/messages/convo/types.ts
@@ -24,9 +24,22 @@ export enum ConvoStatus {
 }
 
 export enum ConvoItemError {
-  HistoryFailed = 'historyFailed',
-  PollFailed = 'pollFailed',
+  /**
+   * Generic error
+   */
   Network = 'network',
+  /**
+   * Error connecting to event firehose
+   */
+  FirehoseFailed = 'firehoseFailed',
+  /**
+   * Error fetching past messages
+   */
+  HistoryFailed = 'historyFailed',
+  /**
+   * Error sending new message
+   */
+  PendingFailed = 'pendingFailed',
 }
 
 export enum ConvoErrorCode {
@@ -89,11 +102,6 @@ export type ConvoItem =
         | null
     }
   | {
-      type: 'pending-retry'
-      key: string
-      retry: () => void
-    }
-  | {
       type: 'error-recoverable'
       key: string
       code: ConvoItemError