diff --git a/apps/audius-client/packages/common/src/store/pages/chat/index.ts b/apps/audius-client/packages/common/src/store/pages/chat/index.ts index 0edab0c8f6b..d92577b5120 100644 --- a/apps/audius-client/packages/common/src/store/pages/chat/index.ts +++ b/apps/audius-client/packages/common/src/store/pages/chat/index.ts @@ -3,3 +3,4 @@ export * as chatSelectors from './selectors' export { sagas as chatSagas } from './sagas' export { chatMiddleware } from './middleware' export * from './types' +export { makeChatId } from './utils' diff --git a/apps/audius-client/packages/common/src/store/pages/chat/sagas.ts b/apps/audius-client/packages/common/src/store/pages/chat/sagas.ts index 015ebe4eb5c..f953e8889ff 100644 --- a/apps/audius-client/packages/common/src/store/pages/chat/sagas.ts +++ b/apps/audius-client/packages/common/src/store/pages/chat/sagas.ts @@ -18,7 +18,7 @@ import { ulid } from 'ulid' import { ID } from 'models/Identifiers' import { Status } from 'models/Status' import { getAccountUser, getUserId } from 'store/account/selectors' -import { toastActions } from 'store/index' +import { makeChatId, toastActions } from 'store/index' import { decodeHashId, encodeHashId, removeNullable } from '../../../utils' import { cacheUsersActions } from '../../cache' @@ -205,7 +205,7 @@ function* doSetMessageReaction(action: ReturnType) { } function* doCreateChat(action: ReturnType) { - const { userIds } = action.payload + const { userIds, skipNavigation } = action.payload try { const audiusSdk = yield* getContext('audiusSdk') const sdk = yield* call(audiusSdk) @@ -214,23 +214,19 @@ function* doCreateChat(action: ReturnType) { throw new Error('User not found') } // Try to get existing chat: - const chatId = [currentUserId, ...userIds] - .map((id) => encodeHashId(id)) - .sort() - .join(':') + const chatId = makeChatId([currentUserId, ...userIds]) - // Optimistically navigate - if we fail we'll toast - yield* put(goToChat({ chatId })) + // Optimistically go to the chat. If we fail to create it, we'll toast + if (!skipNavigation) { + yield* put(goToChat({ chatId })) + } try { yield* call(doFetchChatIfNecessary, { chatId }) } catch {} const existingChat = yield* select((state) => getChat(state, chatId)) - if (existingChat) { - // Simply navigate to the existing chat - yield* put(goToChat({ chatId: existingChat.chat_id })) - } else { - // Create new chat and navigate to it + if (!existingChat) { + // Create new chat yield* call([sdk.chats, sdk.chats.create], { userId: encodeHashId(currentUserId), invitedUserIds: userIds.map((id) => encodeHashId(id)) diff --git a/apps/audius-client/packages/common/src/store/pages/chat/slice.ts b/apps/audius-client/packages/common/src/store/pages/chat/slice.ts index 30719f794d5..b4b4b0dd4f5 100644 --- a/apps/audius-client/packages/common/src/store/pages/chat/slice.ts +++ b/apps/audius-client/packages/common/src/store/pages/chat/slice.ts @@ -126,7 +126,10 @@ const slice = createSlice({ name: 'application/pages/chat', initialState, reducers: { - createChat: (_state, _action: PayloadAction<{ userIds: ID[] }>) => { + createChat: ( + _state, + _action: PayloadAction<{ userIds: ID[]; skipNavigation?: boolean }> + ) => { // triggers saga }, createChatSucceeded: (state, action: PayloadAction<{ chat: UserChat }>) => { diff --git a/apps/audius-client/packages/common/src/store/pages/chat/utils.ts b/apps/audius-client/packages/common/src/store/pages/chat/utils.ts new file mode 100644 index 00000000000..0ceddb4eb85 --- /dev/null +++ b/apps/audius-client/packages/common/src/store/pages/chat/utils.ts @@ -0,0 +1,6 @@ +import { ID } from 'models/Identifiers' +import { encodeHashId } from 'utils/hashIds' + +export const makeChatId = (userIds: ID[]) => { + return userIds.map(encodeHashId).sort().join(':') +} diff --git a/apps/audius-client/packages/mobile/src/components/inbox-unavailable-drawer/InboxUnavailableDrawer.tsx b/apps/audius-client/packages/mobile/src/components/inbox-unavailable-drawer/InboxUnavailableDrawer.tsx index 198872cd712..4dfa8d2e515 100644 --- a/apps/audius-client/packages/mobile/src/components/inbox-unavailable-drawer/InboxUnavailableDrawer.tsx +++ b/apps/audius-client/packages/mobile/src/components/inbox-unavailable-drawer/InboxUnavailableDrawer.tsx @@ -138,7 +138,7 @@ const DrawerContent = ({ data }: DrawerContentProps) => { }, [closeDrawer]) const handleTipPress = useCallback(() => { - dispatch(beginTip({ user, source: 'profile' })) + dispatch(beginTip({ user, source: 'inboxUnavailableModal' })) navigation.navigate('TipArtist') closeDrawer() }, [closeDrawer, dispatch, navigation, user]) diff --git a/apps/audius-client/packages/mobile/src/screens/tip-artist-screen/TipSentScreen.tsx b/apps/audius-client/packages/mobile/src/screens/tip-artist-screen/TipSentScreen.tsx index 7428fcbc5e0..2a3d1a4caf9 100644 --- a/apps/audius-client/packages/mobile/src/screens/tip-artist-screen/TipSentScreen.tsx +++ b/apps/audius-client/packages/mobile/src/screens/tip-artist-screen/TipSentScreen.tsx @@ -2,13 +2,15 @@ import { useCallback } from 'react' import type { SolanaWalletAddress } from '@audius/common' import { + makeChatId, + chatActions, formatNumberCommas, accountSelectors, tippingSelectors } from '@audius/common' import { useNavigation } from '@react-navigation/native' import { Platform } from 'react-native' -import { useSelector } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import IconCheck from 'app/assets/images/iconCheck.svg' import IconRemove from 'app/assets/images/iconRemove.svg' @@ -48,6 +50,7 @@ const useStyles = makeStyles(({ spacing }) => ({ })) export const TipSentScreen = () => { + const dispatch = useDispatch() const account = useSelector(getAccountUser) const { user: recipient, @@ -78,8 +81,23 @@ export const TipSentScreen = () => { } const handleClose = useCallback(() => { - navigation.getParent()?.goBack() - }, [navigation]) + // After success + close, take the user to the chat they were + // attempting to make if they were unlocking DMs by tipping. + // The saga will create the chat once the tip is confirmed + if ( + source === 'inboxUnavailableModal' && + account?.user_id && + recipient?.user_id + ) { + dispatch( + chatActions.goToChat({ + chatId: makeChatId([account.user_id, recipient.user_id]) + }) + ) + } else { + navigation.getParent()?.goBack() + } + }, [account?.user_id, dispatch, navigation, recipient?.user_id, source]) return ( { const dispatch = useDispatch() const sendStatus = useSelector(getSendStatus) const previousSendStatus = usePrevious(sendStatus) + const { user: recipient, source } = useSelector(getSendTipData) + const currentUserId = useSelector(accountSelectors.getUserId) const audioFeaturesDegradedText = useRemoteVar( StringKeys.AUDIO_FEATURES_DEGRADED_TEXT ) const onClose = useCallback(() => { + // After success + close, take the user to the chat they were + // attempting to make if they were unlocking DMs by tipping. + // The saga will create the chat once the tip is confirmed + if ( + source === 'inboxUnavailableModal' && + sendStatus === 'SUCCESS' && + recipient?.user_id && + currentUserId + ) { + dispatch( + chatActions.goToChat({ + chatId: makeChatId([currentUserId, recipient.user_id]) + }) + ) + } dispatch(resetSend()) - }, [dispatch]) + }, [currentUserId, dispatch, recipient?.user_id, sendStatus, source]) useEffect(() => { if (sendStatus !== null) {