From 6a2ea48d81c22e448f7a0e13e152999e55343e10 Mon Sep 17 00:00:00 2001 From: Cindy Green Date: Wed, 6 May 2026 16:12:45 -0400 Subject: [PATCH 1/2] Leave project after navigation so effects are not running after hypercore is closed and we don't run into unfixable errors. --- .../screens/RemovedFromProjectBottomSheet.tsx | 63 +++++++++---------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/src/frontend/screens/RemovedFromProjectBottomSheet.tsx b/src/frontend/screens/RemovedFromProjectBottomSheet.tsx index cfe7bcfc59..760ab4dc0f 100644 --- a/src/frontend/screens/RemovedFromProjectBottomSheet.tsx +++ b/src/frontend/screens/RemovedFromProjectBottomSheet.tsx @@ -72,47 +72,42 @@ export const RemovedFromProjectBottomSheet = ({ - {leaveProject.status === 'pending' || - createProject.status === 'pending' ? ( + {createProject.status === 'pending' ? ( ) : ( { - leaveProject.mutate( - {projectId}, - { - onSuccess: () => { - if (!defaultProject) { - // The user should ALWAYS have a default (solo) project. This was not implemented until after v6. So this creates one if it does not exist - createProject.mutate(undefined, { - onError: err => { - const firstProject = projects[0]; - //if there is a project just open that project - if (firstProject) { - setActiveProjectId(firstProject.projectId); - navigation.popToTop(); - return; - } - navigation.navigate('ErrorBottomSheet', { - error: toError( - err, - 'Error creating default project', - ), - }); - }, - onSuccess: newDefaultProjectId => { - setActiveProjectId(newDefaultProjectId); - navigation.popToTop(); - }, - }); - return; - } - setActiveProjectId(defaultProject.projectId); + if (defaultProject) { + setActiveProjectId(defaultProject.projectId); + // Navigate away before leaveProject closes the hypercores on + // the backend in order to unmount subscribed components + // and run cleanup, avoiding SESSION_CLOSED errors + navigation.popToTop(); + leaveProject.mutate({projectId}); + return; + } + // The user should ALWAYS have a default (solo) project. This was + // not implemented until after v6. So this creates one if it does not exist + createProject.mutate(undefined, { + onError: err => { + const firstProject = projects[0]; + if (firstProject) { + setActiveProjectId(firstProject.projectId); navigation.popToTop(); - }, + leaveProject.mutate({projectId}); + return; + } + navigation.navigate('ErrorBottomSheet', { + error: toError(err, 'Error creating default project'), + }); }, - ); + onSuccess: newDefaultProjectId => { + setActiveProjectId(newDefaultProjectId); + navigation.popToTop(); + leaveProject.mutate({projectId}); + }, + }); }} text={formatMessage(m.close)} /> From c8448b49e43183486e19e37243bb0881af786d47 Mon Sep 17 00:00:00 2001 From: Cindy Green Date: Wed, 27 May 2026 16:33:31 -0400 Subject: [PATCH 2/2] Removes project id from nav params so that the project id is the active project and not a stale one. --- .../screens/RemovedFromProjectBottomSheet.tsx | 66 ++++++++++--------- .../ProjectRemovalListener.tsx | 10 +-- src/frontend/sharedTypes/navigation.ts | 2 +- 3 files changed, 38 insertions(+), 40 deletions(-) diff --git a/src/frontend/screens/RemovedFromProjectBottomSheet.tsx b/src/frontend/screens/RemovedFromProjectBottomSheet.tsx index 760ab4dc0f..3e9be2f909 100644 --- a/src/frontend/screens/RemovedFromProjectBottomSheet.tsx +++ b/src/frontend/screens/RemovedFromProjectBottomSheet.tsx @@ -12,6 +12,7 @@ import { useOwnRoleInProject, useProjectSettings, } from '@comapeo/core-react'; +import {useActiveProject} from '../contexts/ActiveProjectContext'; import {useActiveProjectIdActions} from '../contexts/ActiveProjectIdStoreContext'; import {UIActivityIndicator} from 'react-native-indicators'; import {ColorCard} from '../sharedComponents/ColorCard'; @@ -34,11 +35,10 @@ const m = defineMessages({ }); export const RemovedFromProjectBottomSheet = ({ - route, navigation, }: NativeRootNavigationProps<'RemovedFromProjectBottomSheet'>) => { const {formatMessage} = useIntl(); - const {projectId} = route.params; + const {projectId} = useActiveProject(); const { data: {reason}, } = useOwnRoleInProject({projectId}); @@ -72,42 +72,46 @@ export const RemovedFromProjectBottomSheet = ({ - {createProject.status === 'pending' ? ( + {leaveProject.status === 'pending' || + createProject.status === 'pending' ? ( ) : ( { - if (defaultProject) { - setActiveProjectId(defaultProject.projectId); - // Navigate away before leaveProject closes the hypercores on - // the backend in order to unmount subscribed components - // and run cleanup, avoiding SESSION_CLOSED errors - navigation.popToTop(); - leaveProject.mutate({projectId}); - return; - } - // The user should ALWAYS have a default (solo) project. This was - // not implemented until after v6. So this creates one if it does not exist - createProject.mutate(undefined, { - onError: err => { - const firstProject = projects[0]; - if (firstProject) { - setActiveProjectId(firstProject.projectId); + leaveProject.mutate( + {projectId}, + { + onSuccess: () => { + if (!defaultProject) { + // The user should ALWAYS have a default (solo) project. This was not implemented until after v6. So this creates one if it does not exist + createProject.mutate(undefined, { + onError: err => { + const firstProject = projects[0]; + if (firstProject) { + setActiveProjectId(firstProject.projectId); + navigation.popToTop(); + return; + } + navigation.navigate('ErrorBottomSheet', { + error: toError( + err, + 'Error creating default project', + ), + }); + }, + onSuccess: newDefaultProjectId => { + setActiveProjectId(newDefaultProjectId); + navigation.popToTop(); + }, + }); + return; + } + setActiveProjectId(defaultProject.projectId); navigation.popToTop(); - leaveProject.mutate({projectId}); - return; - } - navigation.navigate('ErrorBottomSheet', { - error: toError(err, 'Error creating default project'), - }); + }, }, - onSuccess: newDefaultProjectId => { - setActiveProjectId(newDefaultProjectId); - navigation.popToTop(); - leaveProject.mutate({projectId}); - }, - }); + ); }} text={formatMessage(m.close)} /> diff --git a/src/frontend/sharedComponents/ProjectRemovalListener.tsx b/src/frontend/sharedComponents/ProjectRemovalListener.tsx index 307ff9d7cb..3bd7cfab48 100644 --- a/src/frontend/sharedComponents/ProjectRemovalListener.tsx +++ b/src/frontend/sharedComponents/ProjectRemovalListener.tsx @@ -26,16 +26,10 @@ export const ProjectRemovalListener = () => { navigation.dispatch( CommonActions.reset({ index: 1, - routes: [ - {name: 'Home'}, - { - name: 'RemovedFromProjectBottomSheet', - params: {projectId}, - }, - ], + routes: [{name: 'Home'}, {name: 'RemovedFromProjectBottomSheet'}], }), ); - }, [projectId, navigation]); + }, [navigation]); //checks on first open of project that the user has not been blocked React.useEffect(() => { diff --git a/src/frontend/sharedTypes/navigation.ts b/src/frontend/sharedTypes/navigation.ts index cf62f3c3ea..c94f9f6d9e 100644 --- a/src/frontend/sharedTypes/navigation.ts +++ b/src/frontend/sharedTypes/navigation.ts @@ -157,7 +157,7 @@ export type RootStackParamsList = { InviteReceived: {inviteId: string}; InviteSuccessfullyAccepted: {projectName: string; projectId: string}; InviteCanceled: {projectName: string}; - RemovedFromProjectBottomSheet: {projectId: string}; + RemovedFromProjectBottomSheet: undefined; ObservationMetadata: {observationId: string}; ErrorBottomSheet: {error: Error}; BackgroundMapErrorBottomSheet: {title: string; description: string};