parent
1e484c6318
commit
051e897a2b
|
@ -0,0 +1,54 @@
|
|||
import React from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {ConvoError, ConvoItem} from '#/state/messages/convo'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
|
||||
import {InlineLinkText} from '#/components/Link'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
||||
export function MessageListError({
|
||||
item,
|
||||
}: {
|
||||
item: ConvoItem & {type: 'error-recoverable'}
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const message = React.useMemo(() => {
|
||||
return {
|
||||
[ConvoError.HistoryFailed]: _(msg`Failed to load past messages.`),
|
||||
}[item.code]
|
||||
}, [_, item.code])
|
||||
|
||||
return (
|
||||
<View style={[a.py_md, a.align_center]}>
|
||||
<View
|
||||
style={[
|
||||
a.align_center,
|
||||
a.pt_md,
|
||||
a.pb_lg,
|
||||
a.px_3xl,
|
||||
a.rounded_md,
|
||||
t.atoms.bg_contrast_25,
|
||||
{maxWidth: 300},
|
||||
]}>
|
||||
<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>
|
||||
</View>
|
||||
)
|
||||
}
|
|
@ -17,6 +17,7 @@ import {useChat} from '#/state/messages'
|
|||
import {ConvoItem, ConvoStatus} from '#/state/messages/convo'
|
||||
import {useSetMinimalShellMode} from '#/state/shell'
|
||||
import {MessageInput} from '#/screens/Messages/Conversation/MessageInput'
|
||||
import {MessageListError} from '#/screens/Messages/Conversation/MessageListError'
|
||||
import {atoms as a} from '#/alf'
|
||||
import {Button, ButtonText} from '#/components/Button'
|
||||
import {MessageItem} from '#/components/dms/MessageItem'
|
||||
|
@ -63,6 +64,8 @@ function renderItem({item}: {item: ConvoItem}) {
|
|||
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} />
|
||||
}
|
||||
|
||||
return null
|
||||
|
|
|
@ -25,6 +25,10 @@ export enum ConvoStatus {
|
|||
Suspended = 'suspended',
|
||||
}
|
||||
|
||||
export enum ConvoError {
|
||||
HistoryFailed = 'historyFailed',
|
||||
}
|
||||
|
||||
export type ConvoItem =
|
||||
| {
|
||||
type: 'message' | 'pending-message'
|
||||
|
@ -49,6 +53,17 @@ export type ConvoItem =
|
|||
key: string
|
||||
retry: () => void
|
||||
}
|
||||
| {
|
||||
type: 'error-recoverable'
|
||||
key: string
|
||||
code: ConvoError
|
||||
retry: () => void
|
||||
}
|
||||
| {
|
||||
type: 'error-fatal'
|
||||
code: ConvoError
|
||||
key: string
|
||||
}
|
||||
|
||||
export type ConvoState =
|
||||
| {
|
||||
|
@ -169,6 +184,7 @@ export class Convo {
|
|||
> = new Map()
|
||||
private deletedMessages: Set<string> = new Set()
|
||||
private footerItems: Map<string, ConvoItem> = new Map()
|
||||
private headerItems: Map<string, ConvoItem> = new Map()
|
||||
|
||||
private pendingEventIngestion: Promise<void> | undefined
|
||||
private isProcessingPendingMessages = false
|
||||
|
@ -366,6 +382,13 @@ export class Convo {
|
|||
*/
|
||||
if (this.isFetchingHistory) return
|
||||
|
||||
/*
|
||||
* If we've rendered a retry state for history fetching, exit. Upon retry,
|
||||
* this will be removed and we'll try again.
|
||||
*/
|
||||
if (this.headerItems.has(ConvoError.HistoryFailed)) return
|
||||
|
||||
try {
|
||||
this.isFetchingHistory = true
|
||||
this.commit()
|
||||
|
||||
|
@ -375,6 +398,7 @@ export class Convo {
|
|||
*/
|
||||
if (this.pastMessages.size > 0) {
|
||||
await new Promise(y => setTimeout(y, 500))
|
||||
// throw new Error('UNCOMMENT TO TEST RETRY')
|
||||
}
|
||||
|
||||
const response = await this.agent.api.chat.bsky.convo.getMessages(
|
||||
|
@ -391,7 +415,7 @@ export class Convo {
|
|||
)
|
||||
const {cursor, messages} = response.data
|
||||
|
||||
this.historyCursor = cursor || null
|
||||
this.historyCursor = cursor ?? null
|
||||
|
||||
for (const message of messages) {
|
||||
if (
|
||||
|
@ -408,10 +432,23 @@ export class Convo {
|
|||
}
|
||||
}
|
||||
}
|
||||
} catch (e: any) {
|
||||
logger.error('Convo: failed to fetch message history')
|
||||
|
||||
this.headerItems.set(ConvoError.HistoryFailed, {
|
||||
type: 'error-recoverable',
|
||||
key: ConvoError.HistoryFailed,
|
||||
code: ConvoError.HistoryFailed,
|
||||
retry: () => {
|
||||
this.headerItems.delete(ConvoError.HistoryFailed)
|
||||
this.fetchMessageHistory()
|
||||
},
|
||||
})
|
||||
} finally {
|
||||
this.isFetchingHistory = false
|
||||
this.commit()
|
||||
}
|
||||
}
|
||||
|
||||
private async pollEvents() {
|
||||
if (
|
||||
|
@ -730,6 +767,10 @@ export class Convo {
|
|||
}
|
||||
})
|
||||
|
||||
this.headerItems.forEach(item => {
|
||||
items.push(item)
|
||||
})
|
||||
|
||||
return items
|
||||
.filter(item => {
|
||||
if (isConvoItemMessage(item)) {
|
||||
|
|
Loading…
Reference in New Issue