[Chat] Handle new chat notification reasons (#10530)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+20
-8
@@ -22,8 +22,9 @@ import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher'
|
||||
import {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle'
|
||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||
import {
|
||||
type ChatNotificationPayload,
|
||||
getNotificationPayload,
|
||||
type NotificationPayload,
|
||||
isChatNotificationPayload,
|
||||
notificationToURL,
|
||||
storePayloadForAccountSwitch,
|
||||
} from '#/lib/hooks/useNotificationHandler'
|
||||
@@ -926,14 +927,14 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
|
||||
const linkingUrl = Linking.useLinkingURL()
|
||||
|
||||
/**
|
||||
* Handle navigation to a conversation, or prepares for account switch.
|
||||
* Handle navigation to the messages tab, or prepares for account switch.
|
||||
*
|
||||
* Non-reactive because we need the latest data from some hooks
|
||||
* after an async call - sfn
|
||||
*/
|
||||
const handleChatMessage = useNonReactiveCallback(
|
||||
(payload: Extract<NotificationPayload, {reason: 'chat-message'}>) => {
|
||||
notyLogger.debug(`handleChatMessage`, {payload})
|
||||
const handleChatNotification = useNonReactiveCallback(
|
||||
(payload: ChatNotificationPayload) => {
|
||||
notyLogger.debug(`handleChatNotification`, {payload})
|
||||
|
||||
if (payload.recipientDid !== currentAccount?.did) {
|
||||
// handled in useNotificationHandler after account switch finishes
|
||||
@@ -946,7 +947,13 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
|
||||
} else {
|
||||
setShowLoggedOut(true)
|
||||
}
|
||||
} else {
|
||||
} else if (
|
||||
payload.reason === 'chat-message' ||
|
||||
payload.reason === 'chat-reaction' ||
|
||||
payload.reason === 'chat-added-to-group'
|
||||
) {
|
||||
// chat-added-to-group routes to the convo because the recipient was
|
||||
// just added and now has access.
|
||||
// @ts-expect-error nested navigators aren't typed -sfn
|
||||
navigate('MessagesTab', {
|
||||
screen: 'Messages',
|
||||
@@ -954,6 +961,11 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
|
||||
pushToConversation: payload.convoId,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
// chat-removed-from-group, chat-join-request-rejected: the convo is
|
||||
// no longer accessible to the recipient, so just open the list.
|
||||
// @ts-expect-error nested navigators aren't typed -sfn
|
||||
navigate('MessagesTab', {screen: 'Messages'})
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -989,8 +1001,8 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
|
||||
causedBoot: true,
|
||||
})
|
||||
|
||||
if (payload.reason === 'chat-message') {
|
||||
handleChatMessage(payload)
|
||||
if (isChatNotificationPayload(payload)) {
|
||||
handleChatNotification(payload)
|
||||
} else {
|
||||
const path = notificationToURL(payload)
|
||||
|
||||
|
||||
@@ -30,6 +30,9 @@ export type NotificationReason =
|
||||
| 'quote'
|
||||
| 'chat-message'
|
||||
| 'chat-reaction'
|
||||
| 'chat-added-to-group'
|
||||
| 'chat-removed-from-group'
|
||||
| 'chat-join-request-rejected'
|
||||
| 'starterpack-joined'
|
||||
| 'like-via-repost'
|
||||
| 'repost-via-repost'
|
||||
@@ -37,6 +40,8 @@ export type NotificationReason =
|
||||
| 'unverified'
|
||||
| 'subscribed-post'
|
||||
|
||||
type ChatNotificationReason = Extract<NotificationReason, `chat-${string}`>
|
||||
|
||||
/**
|
||||
* Manually overridden type, but retains the possibility of
|
||||
* `notification.request.trigger.payload` being `undefined`, as specified in
|
||||
@@ -45,7 +50,7 @@ export type NotificationReason =
|
||||
export type NotificationPayload =
|
||||
| undefined
|
||||
| {
|
||||
reason: Exclude<NotificationReason, 'chat-message' | 'chat-reaction'>
|
||||
reason: Exclude<NotificationReason, ChatNotificationReason>
|
||||
uri: string
|
||||
subject: string
|
||||
recipientDid: string
|
||||
@@ -62,6 +67,25 @@ export type NotificationPayload =
|
||||
messageId: string
|
||||
recipientDid: string
|
||||
}
|
||||
| {
|
||||
reason:
|
||||
| 'chat-added-to-group'
|
||||
| 'chat-removed-from-group'
|
||||
| 'chat-join-request-rejected'
|
||||
convoId: string
|
||||
recipientDid: string
|
||||
}
|
||||
|
||||
export type ChatNotificationPayload = Extract<
|
||||
NonNullable<NotificationPayload>,
|
||||
{reason: ChatNotificationReason}
|
||||
>
|
||||
|
||||
export function isChatNotificationPayload(
|
||||
payload: NonNullable<NotificationPayload>,
|
||||
): payload is ChatNotificationPayload {
|
||||
return payload.reason.startsWith('chat-')
|
||||
}
|
||||
|
||||
const DEFAULT_HANDLER_OPTIONS = {
|
||||
shouldShowBanner: false,
|
||||
@@ -199,10 +223,7 @@ export function useNotificationsHandler() {
|
||||
const handleNotification = (payload?: NotificationPayload) => {
|
||||
if (!payload) return
|
||||
|
||||
if (
|
||||
payload.reason === 'chat-message' ||
|
||||
payload.reason === 'chat-reaction'
|
||||
) {
|
||||
if (isChatNotificationPayload(payload)) {
|
||||
logger.debug(`useNotificationsHandler: handling chat notification`, {
|
||||
payload,
|
||||
})
|
||||
@@ -220,7 +241,13 @@ export function useNotificationsHandler() {
|
||||
} else {
|
||||
setShowLoggedOut(true)
|
||||
}
|
||||
} else {
|
||||
} else if (
|
||||
payload.reason === 'chat-message' ||
|
||||
payload.reason === 'chat-reaction' ||
|
||||
payload.reason === 'chat-added-to-group'
|
||||
) {
|
||||
// chat-added-to-group routes to the convo because the recipient was
|
||||
// just added and now has access.
|
||||
navigation.dispatch(state => {
|
||||
if (state.routes[0].name === 'Messages') {
|
||||
if (
|
||||
@@ -253,6 +280,12 @@ export function useNotificationsHandler() {
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// chat-removed-from-group, chat-join-request-rejected: the convo is
|
||||
// no longer accessible to the recipient, so just open the list.
|
||||
navigation.dispatch(
|
||||
CommonActions.navigate('MessagesTab', {screen: 'Messages'}),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
const url = notificationToURL(payload)
|
||||
@@ -280,11 +313,16 @@ export function useNotificationsHandler() {
|
||||
logger.debug('useNotificationsHandler: incoming', {e, payload})
|
||||
|
||||
if (
|
||||
(payload.reason === 'chat-message' ||
|
||||
payload.reason === 'chat-reaction') &&
|
||||
isChatNotificationPayload(payload) &&
|
||||
payload.recipientDid === currentAccount?.did
|
||||
) {
|
||||
const shouldAlert = payload.convoId !== currentConvoId
|
||||
// chat-removed-from-group / chat-join-request-rejected always alert,
|
||||
// even if the recipient is currently viewing the affected convo -
|
||||
// they need to know they were removed/rejected.
|
||||
const shouldAlert =
|
||||
payload.reason === 'chat-removed-from-group' ||
|
||||
payload.reason === 'chat-join-request-rejected' ||
|
||||
payload.convoId !== currentConvoId
|
||||
return {
|
||||
shouldShowList: shouldAlert,
|
||||
shouldShowBanner: shouldAlert,
|
||||
@@ -352,8 +390,8 @@ export function useNotificationsHandler() {
|
||||
// Whenever there's a stored payload, that means we had to switch accounts before handling the notification.
|
||||
// Whenever currentAccount changes, we should try to handle it again.
|
||||
if (
|
||||
(storedAccountSwitchPayload?.reason === 'chat-message' ||
|
||||
storedAccountSwitchPayload?.reason === 'chat-reaction') &&
|
||||
storedAccountSwitchPayload &&
|
||||
isChatNotificationPayload(storedAccountSwitchPayload) &&
|
||||
currentAccount?.did === storedAccountSwitchPayload.recipientDid
|
||||
) {
|
||||
handleNotification(storedAccountSwitchPayload)
|
||||
@@ -442,6 +480,9 @@ export function notificationToURL(payload: NotificationPayload): string | null {
|
||||
}
|
||||
case 'chat-message':
|
||||
case 'chat-reaction':
|
||||
case 'chat-added-to-group':
|
||||
case 'chat-removed-from-group':
|
||||
case 'chat-join-request-rejected':
|
||||
// should be handled separately
|
||||
return null
|
||||
case 'verified':
|
||||
|
||||
Reference in New Issue
Block a user