From 58d1b02d3af64a7f5a904e2f4760f0b92125ea11 Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Fri, 21 Apr 2023 12:27:51 -0400 Subject: [PATCH] Fix the query undefined comparison when threadId prop is not set by the navigation library (#7302) --- app/actions/local/thread.ts | 15 +++++++------- app/actions/remote/channel.ts | 5 ++--- app/actions/remote/team.ts | 5 ++--- .../leave_channel_label.tsx | 5 ++--- app/components/markdown/hashtag/index.tsx | 5 ++--- app/queries/servers/thread.ts | 8 ++++++-- app/screens/navigation.ts | 10 ++++++++++ .../thread/thread_follow_button/index.ts | 20 ++++++++++++++++--- app/utils/error_handling.ts | 3 ++- 9 files changed, 51 insertions(+), 25 deletions(-) diff --git a/app/actions/local/thread.ts b/app/actions/local/thread.ts index 6a02763f3..926ff1fc4 100644 --- a/app/actions/local/thread.ts +++ b/app/actions/local/thread.ts @@ -101,6 +101,14 @@ export const switchToThread = async (serverUrl: string, rootId: string, isFromNo } } + if (isFromNotification) { + await dismissAllModalsAndPopToRoot(); + await NavigationStore.waitUntilScreenIsTop(Screens.HOME); + if (switchingTeams && isTabletDevice) { + DeviceEventEmitter.emit(Navigation.NAVIGATION_HOME, Screens.GLOBAL_THREADS); + } + } + // Modal right buttons const rightButtons = []; @@ -137,13 +145,6 @@ export const switchToThread = async (serverUrl: string, rootId: string, isFromNo EphemeralStore.setCurrentThreadId(rootId); - if (isFromNotification) { - await dismissAllModalsAndPopToRoot(); - await NavigationStore.waitUntilScreenIsTop(Screens.HOME); - if (switchingTeams && isTabletDevice) { - DeviceEventEmitter.emit(Navigation.NAVIGATION_HOME, Screens.GLOBAL_THREADS); - } - } goToScreen(Screens.THREAD, '', {rootId}, { topBar: { title: { diff --git a/app/actions/remote/channel.ts b/app/actions/remote/channel.ts index 111168428..8f3ce7977 100644 --- a/app/actions/remote/channel.ts +++ b/app/actions/remote/channel.ts @@ -21,7 +21,7 @@ import {queryDisplayNamePreferences} from '@queries/servers/preference'; import {getCommonSystemValues, getConfig, getCurrentChannelId, getCurrentTeamId, getCurrentUserId, getLicense, setCurrentChannelId, setCurrentTeamAndChannelId} from '@queries/servers/system'; import {getNthLastChannelFromTeam, getMyTeamById, getTeamByName, queryMyTeams, removeChannelFromTeamHistory} from '@queries/servers/team'; import {getCurrentUser} from '@queries/servers/user'; -import {dismissAllModals, popToRoot} from '@screens/navigation'; +import {dismissAllModalsAndPopToRoot} from '@screens/navigation'; import EphemeralStore from '@store/ephemeral_store'; import {setTeamLoading} from '@store/team_load_store'; import {generateChannelNameFromDisplayName, getDirectChannelName, isDMorGM} from '@utils/channel'; @@ -1423,8 +1423,7 @@ export const handleKickFromChannel = async (serverUrl: string, channelId: string if (currentServer?.url === serverUrl) { const channel = await getChannelById(database, channelId); DeviceEventEmitter.emit(event, channel?.displayName); - await dismissAllModals(); - await popToRoot(); + await dismissAllModalsAndPopToRoot(); } const tabletDevice = await isTablet(); diff --git a/app/actions/remote/team.ts b/app/actions/remote/team.ts index aa3006887..c7342e5c4 100644 --- a/app/actions/remote/team.ts +++ b/app/actions/remote/team.ts @@ -13,7 +13,7 @@ import {prepareCategoriesAndCategoriesChannels} from '@queries/servers/categorie import {prepareMyChannelsForTeam, getDefaultChannelForTeam} from '@queries/servers/channel'; import {prepareCommonSystemValues, getCurrentTeamId, getCurrentUserId} from '@queries/servers/system'; import {addTeamToTeamHistory, prepareDeleteTeam, prepareMyTeams, getNthLastChannelFromTeam, queryTeamsById, getLastTeam, getTeamById, removeTeamFromTeamHistory, queryMyTeams} from '@queries/servers/team'; -import {dismissAllModals, popToRoot} from '@screens/navigation'; +import {dismissAllModalsAndPopToRoot} from '@screens/navigation'; import EphemeralStore from '@store/ephemeral_store'; import {setTeamLoading} from '@store/team_load_store'; import {isTablet} from '@utils/helpers'; @@ -461,8 +461,7 @@ export async function handleKickFromTeam(serverUrl: string, teamId: string) { if (currentServer === serverUrl) { const team = await getTeamById(database, teamId); DeviceEventEmitter.emit(Events.LEAVE_TEAM, team?.displayName); - await dismissAllModals(); - await popToRoot(); + await dismissAllModalsAndPopToRoot(); } await removeTeamFromTeamHistory(operator, teamId); diff --git a/app/components/channel_actions/leave_channel_label/leave_channel_label.tsx b/app/components/channel_actions/leave_channel_label/leave_channel_label.tsx index 009c18c39..7daba7ddd 100644 --- a/app/components/channel_actions/leave_channel_label/leave_channel_label.tsx +++ b/app/components/channel_actions/leave_channel_label/leave_channel_label.tsx @@ -12,7 +12,7 @@ import SlideUpPanelItem from '@components/slide_up_panel_item'; import {General} from '@constants'; import {useServerUrl} from '@context/server'; import {useIsTablet} from '@hooks/device'; -import {dismissAllModals, dismissBottomSheet, popToRoot} from '@screens/navigation'; +import {dismissAllModalsAndPopToRoot, dismissBottomSheet} from '@screens/navigation'; type Props = { isOptionItem?: boolean; @@ -31,8 +31,7 @@ const LeaveChannelLabel = ({canLeave, channelId, displayName, isOptionItem, type const close = async () => { await dismissBottomSheet(); if (!isTablet) { - await dismissAllModals(); - popToRoot(); + await dismissAllModalsAndPopToRoot(); } }; diff --git a/app/components/markdown/hashtag/index.tsx b/app/components/markdown/hashtag/index.tsx index dd129b26b..b908978c9 100644 --- a/app/components/markdown/hashtag/index.tsx +++ b/app/components/markdown/hashtag/index.tsx @@ -5,7 +5,7 @@ import React from 'react'; import {DeviceEventEmitter, type StyleProp, Text, type TextStyle} from 'react-native'; import {Navigation, Screens} from '@constants'; -import {popToRoot, dismissAllModals} from '@screens/navigation'; +import {dismissAllModalsAndPopToRoot} from '@screens/navigation'; type HashtagProps = { hashtag: string; @@ -15,8 +15,7 @@ type HashtagProps = { const Hashtag = ({hashtag, linkStyle}: HashtagProps) => { const handlePress = async () => { // Close thread view, permalink view, etc - await dismissAllModals(); - await popToRoot(); + await dismissAllModalsAndPopToRoot(); DeviceEventEmitter.emit(Navigation.NAVIGATE_TO_TAB, { screen: Screens.SEARCH, diff --git a/app/queries/servers/thread.ts b/app/queries/servers/thread.ts index 68ffceab9..9c7b98c19 100644 --- a/app/queries/servers/thread.ts +++ b/app/queries/servers/thread.ts @@ -69,8 +69,8 @@ export const observeThreadById = (database: Database, threadId: string) => { ); }; -export const observeTeamIdByThread = (database: Database, thread: ThreadModel) => { - return observePost(database, thread.id).pipe( +export const observeTeamIdByThreadId = (database: Database, threadId: string) => { + return observePost(database, threadId).pipe( switchMap((post) => { if (!post) { return of$(undefined); @@ -82,6 +82,10 @@ export const observeTeamIdByThread = (database: Database, thread: ThreadModel) = ); }; +export const observeTeamIdByThread = (database: Database, thread: ThreadModel) => { + return observeTeamIdByThreadId(database, thread.id); +}; + export const observeUnreadsAndMentionsInTeam = (database: Database, teamId?: string, includeDmGm?: boolean): Observable<{unreads: boolean; mentions: number}> => { const observeThreads = () => queryThreads(database, teamId, true, includeDmGm). observeWithColumns(['unread_replies', 'unread_mentions']). diff --git a/app/screens/navigation.ts b/app/screens/navigation.ts index b8b8d7506..c96e79c98 100644 --- a/app/screens/navigation.ts +++ b/app/screens/navigation.ts @@ -518,6 +518,7 @@ export async function popToRoot() { export async function dismissAllModalsAndPopToRoot() { await dismissAllModals(); + await dismissAllOverlays(); await popToRoot(); } @@ -531,6 +532,7 @@ export async function dismissAllModalsAndPopToRoot() { */ export async function dismissAllModalsAndPopToScreen(screenId: AvailableScreens, title: string, passProps = {}, options = {}) { await dismissAllModals(); + await dismissAllOverlays(); if (NavigationStore.getScreensInStack().includes(screenId)) { let mergeOptions = options; if (title) { @@ -753,6 +755,14 @@ export async function dismissOverlay(componentId: AvailableScreens) { } } +export async function dismissAllOverlays() { + try { + await Navigation.dismissAllOverlays(); + } catch { + // do nothing + } +} + type BottomSheetArgs = { closeButtonId: string; initialSnapIndex?: number; diff --git a/app/screens/thread/thread_follow_button/index.ts b/app/screens/thread/thread_follow_button/index.ts index bf1335dca..5902c8640 100644 --- a/app/screens/thread/thread_follow_button/index.ts +++ b/app/screens/thread/thread_follow_button/index.ts @@ -6,17 +6,31 @@ import withObservables from '@nozbe/with-observables'; import {of as of$} from 'rxjs'; import {switchMap} from 'rxjs/operators'; -import {observeThreadById} from '@queries/servers/thread'; +import {observeTeamIdByThreadId, observeThreadById} from '@queries/servers/thread'; +import EphemeralStore from '@store/ephemeral_store'; import ThreadFollowButton from './thread_follow_button'; import type {WithDatabaseArgs} from '@typings/database/database'; -const enhanced = withObservables(['threadId'], ({threadId, database}: {threadId: string} & WithDatabaseArgs) => { +type Props = WithDatabaseArgs & { + teamId?: string; + threadId?: string; +}; + +const enhanced = withObservables(['threadId'], ({teamId, threadId, database}: Props) => { + // Fallback in case teamId or threadId are not defined per navigation not setting the props bug. + const thId = threadId || EphemeralStore.getCurrentThreadId(); + const tId = teamId ? of$(teamId) : observeTeamIdByThreadId(database, thId).pipe( + switchMap((t) => of$(t || '')), + ); + return { - isFollowing: observeThreadById(database, threadId).pipe( + isFollowing: observeThreadById(database, thId).pipe( switchMap((thread) => of$(thread?.isFollowing)), ), + threadId: of$(thId), + teamId: tId, }; }); diff --git a/app/utils/error_handling.ts b/app/utils/error_handling.ts index f2b612c7f..6c4f0c806 100644 --- a/app/utils/error_handling.ts +++ b/app/utils/error_handling.ts @@ -9,7 +9,7 @@ import { } from 'react-native-exception-handler'; import {DEFAULT_LOCALE, getTranslations, t} from '@i18n'; -import {dismissAllModals} from '@screens/navigation'; +import {dismissAllModals, dismissAllOverlays} from '@screens/navigation'; import {isBetaApp} from '@utils/general'; import { captureException, @@ -58,6 +58,7 @@ class JavascriptAndNativeErrorHandler { text: translations[t('mobile.error_handler.button')], onPress: async () => { await dismissAllModals(); + await dismissAllOverlays(); }, }], {cancelable: false},