From 25c66ee9e07d66c058d86dd85bcf6ed9c11d72bf Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Thu, 10 Apr 2025 14:07:16 +0200 Subject: [PATCH 01/17] [UX Reliability] Use new modal in ConfirmModal --- src/components/ConfirmModal.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/ConfirmModal.tsx b/src/components/ConfirmModal.tsx index 672b64d76dbcc..e1db1773668cb 100755 --- a/src/components/ConfirmModal.tsx +++ b/src/components/ConfirmModal.tsx @@ -165,6 +165,7 @@ function ConfirmModal({ shouldEnableNewFocusManagement={shouldEnableNewFocusManagement} restoreFocusType={restoreFocusType} shouldHandleNavigationBack={shouldHandleNavigationBack} + shouldUseNewModal > Date: Fri, 18 Apr 2025 15:57:47 +0200 Subject: [PATCH 02/17] Fix perf tests --- tests/perf-test/ReportActionCompose.perf-test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/perf-test/ReportActionCompose.perf-test.tsx b/tests/perf-test/ReportActionCompose.perf-test.tsx index 6f6f05c45461e..832abfea81ae4 100644 --- a/tests/perf-test/ReportActionCompose.perf-test.tsx +++ b/tests/perf-test/ReportActionCompose.perf-test.tsx @@ -21,6 +21,7 @@ jest.mock('@gorhom/portal'); jest.mock('react-native-reanimated', () => ({ ...jest.requireActual('react-native-reanimated/mock'), useAnimatedRef: jest.fn(), + LayoutAnimationConfig: jest.fn(), })); jest.mock('../../src/libs/Navigation/Navigation', () => ({ @@ -56,7 +57,6 @@ jest.mock('@src/libs/actions/EmojiPickerAction', () => { isActive: () => true, }; }); -jest.mock('@components/ConfirmedRoute.tsx'); beforeAll(() => Onyx.init({ From 85cf191201785dafa1153cbf9b692ea0290b6fc6 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Fri, 18 Apr 2025 15:59:43 +0200 Subject: [PATCH 03/17] Bring back ConfirmedRoute mock --- tests/perf-test/ReportActionCompose.perf-test.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/perf-test/ReportActionCompose.perf-test.tsx b/tests/perf-test/ReportActionCompose.perf-test.tsx index 832abfea81ae4..1e2df29ec8332 100644 --- a/tests/perf-test/ReportActionCompose.perf-test.tsx +++ b/tests/perf-test/ReportActionCompose.perf-test.tsx @@ -57,6 +57,7 @@ jest.mock('@src/libs/actions/EmojiPickerAction', () => { isActive: () => true, }; }); +jest.mock('@components/ConfirmedRoute.tsx'); beforeAll(() => Onyx.init({ From 6196c2f816a29a39b05c622cf021b01369b10aba Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Fri, 18 Apr 2025 16:19:41 +0200 Subject: [PATCH 04/17] Fix text changed to plural form --- src/pages/ReportParticipantsPage.tsx | 2 +- src/pages/RoomMembersPage.tsx | 2 +- src/pages/workspace/WorkspaceMembersPage.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/ReportParticipantsPage.tsx b/src/pages/ReportParticipantsPage.tsx index 1b296dcfc9939..374b0d04f9550 100755 --- a/src/pages/ReportParticipantsPage.tsx +++ b/src/pages/ReportParticipantsPage.tsx @@ -226,9 +226,9 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { const accountIDsToRemove = selectedMembers.filter((id) => id !== currentUserAccountID); removeFromGroupChat(report.reportID, accountIDsToRemove); setSearchValue(''); - setSelectedMembers([]); setRemoveMembersConfirmModalVisible(false); InteractionManager.runAfterInteractions(() => { + setSelectedMembers([]); clearUserSearchPhrase(); }); }; diff --git a/src/pages/RoomMembersPage.tsx b/src/pages/RoomMembersPage.tsx index 907f374e84f0b..9d43389e9b2c4 100644 --- a/src/pages/RoomMembersPage.tsx +++ b/src/pages/RoomMembersPage.tsx @@ -115,9 +115,9 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { removeFromRoom(report.reportID, selectedMembers); } setSearchValue(''); - setSelectedMembers([]); setRemoveMembersConfirmModalVisible(false); InteractionManager.runAfterInteractions(() => { + setSelectedMembers([]); clearUserSearchPhrase(); }); }; diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index af1d53fbdb15a..1bfd75b2daf46 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -269,9 +269,9 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson }); } - setSelectedEmployees([]); setRemoveMembersConfirmModalVisible(false); InteractionManager.runAfterInteractions(() => { + setSelectedEmployees([]); removeMembers(accountIDsToRemove, route.params.policyID); }); }; From 2a421341ff6b29726e6844dcc94c39a1dd14265a Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Fri, 18 Apr 2025 16:30:27 +0200 Subject: [PATCH 05/17] Update useOnyx calls to handle missing data gracefully --- src/pages/ReportParticipantsPage.tsx | 10 +++++----- src/pages/RoomMembersPage.tsx | 8 ++++---- src/pages/workspace/WorkspaceMembersPage.tsx | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/pages/ReportParticipantsPage.tsx b/src/pages/ReportParticipantsPage.tsx index 374b0d04f9550..c45e2bcd10a6a 100755 --- a/src/pages/ReportParticipantsPage.tsx +++ b/src/pages/ReportParticipantsPage.tsx @@ -69,12 +69,12 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { const {shouldUseNarrowLayout, isSmallScreenWidth} = useResponsiveLayout(); const selectionListRef = useRef(null); const textInputRef = useRef(null); - const [userSearchPhrase] = useOnyx(ONYXKEYS.ROOM_MEMBERS_USER_SEARCH_PHRASE); - const [reportNameValuePairs] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report?.reportID}`); - const [reportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${report?.reportID}`); + const [userSearchPhrase] = useOnyx(ONYXKEYS.ROOM_MEMBERS_USER_SEARCH_PHRASE, {canBeMissing: true}); + const [reportNameValuePairs] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report?.reportID}`, {canBeMissing: true}); + const [reportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${report?.reportID}`, {canBeMissing: true}); const {selectionMode} = useMobileSelectionMode(); - const [session] = useOnyx(ONYXKEYS.SESSION); - const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST); + const [session] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: false}); + const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {canBeMissing: false}); const currentUserAccountID = Number(session?.accountID); const isCurrentUserAdmin = isGroupChatAdmin(report, currentUserAccountID); const isGroupChat = useMemo(() => isGroupChatUtils(report), [report]); diff --git a/src/pages/RoomMembersPage.tsx b/src/pages/RoomMembersPage.tsx index 9d43389e9b2c4..5af109ce157de 100644 --- a/src/pages/RoomMembersPage.tsx +++ b/src/pages/RoomMembersPage.tsx @@ -48,13 +48,13 @@ type RoomMembersPageProps = WithReportOrNotFoundProps & WithCurrentUserPersonalD function RoomMembersPage({report, policies}: RoomMembersPageProps) { const route = useRoute>(); const styles = useThemeStyles(); - const [session] = useOnyx(ONYXKEYS.SESSION); - const [reportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${report?.reportID}`); + const [session] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: false}); + const [reportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${report?.reportID}`, {canBeMissing: true}); const currentUserAccountID = Number(session?.accountID); const {formatPhoneNumber, translate} = useLocalize(); const [selectedMembers, setSelectedMembers] = useState([]); const [removeMembersConfirmModalVisible, setRemoveMembersConfirmModalVisible] = useState(false); - const [userSearchPhrase] = useOnyx(ONYXKEYS.ROOM_MEMBERS_USER_SEARCH_PHRASE); + const [userSearchPhrase] = useOnyx(ONYXKEYS.ROOM_MEMBERS_USER_SEARCH_PHRASE, {canBeMissing: true}); const [searchValue, setSearchValue] = useState(''); const [didLoadRoomMembers, setDidLoadRoomMembers] = useState(false); const personalDetails = usePersonalDetails(); @@ -68,7 +68,7 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { // We need to use isSmallScreenWidth instead of shouldUseNarrowLayout to use the selection mode only on small screens // eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth const {shouldUseNarrowLayout, isSmallScreenWidth} = useResponsiveLayout(); - const [selectionMode] = useOnyx(ONYXKEYS.MOBILE_SELECTION_MODE); + const [selectionMode] = useOnyx(ONYXKEYS.MOBILE_SELECTION_MODE, {canBeMissing: true}); const canSelectMultiple = isSmallScreenWidth ? selectionMode?.isEnabled : true; useEffect(() => { diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index 1bfd75b2daf46..6f4fb7e316231 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -109,9 +109,9 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson [isOfflineAndNoMemberDataAvailable, personalDetails, policy?.employeeList], ); - const [invitedEmailsToAccountIDsDraft] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MEMBERS_DRAFT}${route.params.policyID.toString()}`); + const [invitedEmailsToAccountIDsDraft] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MEMBERS_DRAFT}${route.params.policyID.toString()}`, {canBeMissing: true}); const {selectionMode} = useMobileSelectionMode(); - const [session] = useOnyx(ONYXKEYS.SESSION); + const [session] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: false}); const currentUserAccountID = Number(session?.accountID); const selectionListRef = useRef(null); const isFocused = useIsFocused(); From 8170546bcfb8e2a75b1591a4ef5c3766831786c4 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 22 Apr 2025 16:43:34 +0200 Subject: [PATCH 06/17] Globally fix text that is changed to plural form --- .../workspace/distanceRates/PolicyDistanceRatesPage.tsx | 7 +++++-- src/pages/workspace/perDiem/WorkspacePerDiemPage.tsx | 9 ++++++--- .../workspace/reportFields/WorkspaceReportFieldsPage.tsx | 8 +++++--- src/pages/workspace/taxes/WorkspaceTaxesPage.tsx | 9 ++++++--- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx index 5adbb3a092ea0..63cd0db167897 100644 --- a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx +++ b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx @@ -1,6 +1,6 @@ import {useIsFocused} from '@react-navigation/native'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; -import {ActivityIndicator, View} from 'react-native'; +import {ActivityIndicator, InteractionManager, View} from 'react-native'; import Button from '@components/Button'; import type {DropdownOption, WorkspaceDistanceRatesBulkActionType} from '@components/ButtonWithDropdownMenu/types'; import ConfirmModal from '@components/ConfirmModal'; @@ -225,8 +225,11 @@ function PolicyDistanceRatesPage({ customUnit, selectedDistanceRates.map((rate) => rate.customUnitRateID), ); - setSelectedDistanceRates([]); setIsDeleteModalVisible(false); + + InteractionManager.runAfterInteractions(() => { + setSelectedDistanceRates([]); + }); }; const toggleRate = (rate: RateForList) => { diff --git a/src/pages/workspace/perDiem/WorkspacePerDiemPage.tsx b/src/pages/workspace/perDiem/WorkspacePerDiemPage.tsx index b0b682f0a8a20..60e6f974a6461 100644 --- a/src/pages/workspace/perDiem/WorkspacePerDiemPage.tsx +++ b/src/pages/workspace/perDiem/WorkspacePerDiemPage.tsx @@ -1,7 +1,7 @@ import {useFocusEffect} from '@react-navigation/native'; import lodashSortBy from 'lodash/sortBy'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; -import {ActivityIndicator, View} from 'react-native'; +import {ActivityIndicator, InteractionManager, View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import Button from '@components/Button'; import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu'; @@ -129,7 +129,7 @@ function WorkspacePerDiemPage({route}: WorkspacePerDiemPageProps) { const policyID = route.params.policyID; const backTo = route.params?.backTo; const policy = usePolicy(policyID); - const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`); + const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`, {canBeMissing: true}); const {selectionMode} = useMobileSelectionMode(); const customUnit = getPerDiemCustomUnit(policy); @@ -244,8 +244,11 @@ function WorkspacePerDiemPage({route}: WorkspacePerDiemPageProps) { const handleDeletePerDiemRates = () => { deleteWorkspacePerDiemRates(policyID, customUnit, selectedPerDiem); - setSelectedPerDiem([]); setDeletePerDiemConfirmModalVisible(false); + + InteractionManager.runAfterInteractions(() => { + setSelectedPerDiem([]); + }); }; const getHeaderButtons = () => { diff --git a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx index 4ae84c7b996b5..0248387ff1cae 100644 --- a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx +++ b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx @@ -1,7 +1,7 @@ import {useFocusEffect, useIsFocused} from '@react-navigation/native'; import {Str} from 'expensify-common'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; -import {ActivityIndicator, View} from 'react-native'; +import {ActivityIndicator, InteractionManager, View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import Button from '@components/Button'; import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu'; @@ -84,7 +84,7 @@ function WorkspaceReportFieldsPage({ const [selectedReportFields, setSelectedReportFields] = useState([]); const [deleteReportFieldsConfirmModalVisible, setDeleteReportFieldsConfirmModalVisible] = useState(false); const hasReportAccountingConnections = hasAccountingConnections(policy); - const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policy?.id}`); + const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policy?.id}`, {canBeMissing: true}); const isSyncInProgress = isConnectionInProgress(connectionSyncProgress, policy); const hasSyncError = shouldShowSyncError(policy, isSyncInProgress); const isConnectedToAccounting = Object.keys(policy?.connections ?? {}).length > 0; @@ -155,9 +155,11 @@ function WorkspaceReportFieldsPage({ const handleDeleteReportFields = () => { const reportFieldKeys = selectedReportFields.map((selectedReportField) => getReportFieldKey(selectedReportField.fieldID)); - setSelectedReportFields([]); deleteReportFields(policyID, reportFieldKeys); setDeleteReportFieldsConfirmModalVisible(false); + InteractionManager.runAfterInteractions(() => { + setSelectedReportFields([]); + }); }; const isLoading = !isOffline && policy === undefined; diff --git a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx index 66112d0baa9e8..8f65a6d015622 100644 --- a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx +++ b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useEffect, useMemo, useState} from 'react'; -import {ActivityIndicator, View} from 'react-native'; +import {ActivityIndicator, InteractionManager, View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import Button from '@components/Button'; import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu'; @@ -65,7 +65,7 @@ function WorkspaceTaxesPage({ const defaultExternalID = policy?.taxRates?.defaultExternalID; const foreignTaxDefault = policy?.taxRates?.foreignTaxDefault; const hasAccountingConnections = hasAccountingConnectionsPolicyUtils(policy); - const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policy?.id}`); + const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policy?.id}`, {canBeMissing: true}); const isSyncInProgress = isConnectionInProgress(connectionSyncProgress, policy); const hasSyncError = shouldShowSyncError(policy, isSyncInProgress); @@ -219,8 +219,11 @@ function WorkspaceTaxesPage({ return; } deletePolicyTaxes(policy, selectedTaxesIDs); - setSelectedTaxesIDs([]); setIsDeleteModalVisible(false); + + InteractionManager.runAfterInteractions(() => { + setSelectedTaxesIDs([]); + }); }, [policy, selectedTaxesIDs]); const toggleTaxes = useCallback( From 06938091ab109fd785bc23705f3b85356a206472 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 23 Apr 2025 10:54:06 +0200 Subject: [PATCH 07/17] Fix remaining cases --- .../workspace/reportFields/ReportFieldsListValuesPage.tsx | 8 +++++--- src/pages/workspace/tags/WorkspaceTagsPage.tsx | 7 +++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx b/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx index 9c84adbafcc76..3ec833c18fc71 100644 --- a/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useMemo, useState} from 'react'; -import {View} from 'react-native'; +import {InteractionManager, View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import Button from '@components/Button'; import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu'; @@ -152,8 +152,6 @@ function ReportFieldsListValuesPage({ }; const handleDeleteValues = () => { - setSelectedValues({}); - const valuesToDelete = selectedValuesArray.reduce((acc, valueName) => { const index = listValues?.indexOf(valueName) ?? -1; @@ -171,6 +169,10 @@ function ReportFieldsListValuesPage({ } setDeleteValuesConfirmModalVisible(false); + + InteractionManager.runAfterInteractions(() => { + setSelectedValues({}); + }); }; const openListValuePage = (valueItem: ValueListItem) => { diff --git a/src/pages/workspace/tags/WorkspaceTagsPage.tsx b/src/pages/workspace/tags/WorkspaceTagsPage.tsx index 6e3a2d258eb25..1a4858a546569 100644 --- a/src/pages/workspace/tags/WorkspaceTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceTagsPage.tsx @@ -1,6 +1,6 @@ import lodashSortBy from 'lodash/sortBy'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; -import {ActivityIndicator, View} from 'react-native'; +import {ActivityIndicator, InteractionManager, View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import Button from '@components/Button'; import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu'; @@ -262,9 +262,12 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) { const selectedTagsArray = Object.keys(selectedTags).filter((key) => selectedTags[key]); const deleteTags = () => { - setSelectedTags({}); deletePolicyTags(policyID, selectedTagsArray); setIsDeleteTagsConfirmModalVisible(false); + + InteractionManager.runAfterInteractions(() => { + setSelectedTags({}); + }); }; const isLoading = !isOffline && policyTags === undefined; From 702b9c9a4e36e820bd4121efc3e901ba743299be Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 23 Apr 2025 10:58:11 +0200 Subject: [PATCH 08/17] Fix confirm modal on categories page --- src/pages/workspace/categories/WorkspaceCategoriesPage.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx index 32d03852ba1d2..9957417ca7141 100644 --- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx +++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx @@ -1,6 +1,6 @@ import lodashSortBy from 'lodash/sortBy'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; -import {ActivityIndicator, View} from 'react-native'; +import {ActivityIndicator, InteractionManager, View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import Button from '@components/Button'; import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu'; @@ -222,9 +222,12 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { const selectedCategoriesArray = Object.keys(selectedCategories).filter((key) => selectedCategories[key]); const handleDeleteCategories = () => { - setSelectedCategories({}); deleteWorkspaceCategories(policyId, selectedCategoriesArray); setDeleteCategoriesConfirmModalVisible(false); + + InteractionManager.runAfterInteractions(() => { + setSelectedCategories({}); + }); }; const getHeaderButtons = () => { From bce873eec009282ffe408f5a667bb71a3782a6aa Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 23 Apr 2025 11:00:51 +0200 Subject: [PATCH 09/17] Fix confirm modal on WorkspaceViewTags page --- src/pages/workspace/tags/WorkspaceViewTagsPage.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx b/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx index 831260db3ace2..b686811eeeba0 100644 --- a/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx @@ -1,6 +1,6 @@ import {useIsFocused} from '@react-navigation/native'; import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; -import {ActivityIndicator, View} from 'react-native'; +import {ActivityIndicator, InteractionManager, View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu'; import type {DropdownOption} from '@components/ButtonWithDropdownMenu/types'; @@ -178,9 +178,12 @@ function WorkspaceViewTagsPage({route}: WorkspaceViewTagsProps) { const selectedTagsArray = Object.keys(selectedTags).filter((key) => selectedTags[key]); const deleteTags = () => { - setSelectedTags({}); deletePolicyTags(policyID, selectedTagsArray); setIsDeleteTagsConfirmModalVisible(false); + + InteractionManager.runAfterInteractions(() => { + setSelectedTags({}); + }); }; const isLoading = !isOffline && policyTags === undefined; From 0d138d4f75896d5346f79bc00a0a1e012f2d1c71 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 23 Apr 2025 11:13:44 +0200 Subject: [PATCH 10/17] Update useOnyx calls with new canBeMissing prop --- src/pages/workspace/categories/WorkspaceCategoriesPage.tsx | 4 ++-- .../workspace/reportFields/ReportFieldsListValuesPage.tsx | 2 +- src/pages/workspace/tags/WorkspaceTagsPage.tsx | 4 ++-- src/pages/workspace/tags/WorkspaceViewTagsPage.tsx | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx index 9957417ca7141..7105bccabdd10 100644 --- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx +++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx @@ -79,8 +79,8 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { const backTo = route.params?.backTo; const policy = usePolicy(policyId); const {selectionMode} = useMobileSelectionMode(); - const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyId}`); - const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policy?.id}`); + const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyId}`, {canBeMissing: true}); + const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policy?.id}`, {canBeMissing: true}); const isSyncInProgress = isConnectionInProgress(connectionSyncProgress, policy); const hasSyncError = shouldShowSyncError(policy, isSyncInProgress); const isConnectedToAccounting = Object.keys(policy?.connections ?? {}).length > 0; diff --git a/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx b/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx index 3ec833c18fc71..6ff3f058dee91 100644 --- a/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx @@ -71,7 +71,7 @@ function ReportFieldsListValuesPage({ // See https://github.com/Expensify/App/issues/48724 for more details // eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth const {isSmallScreenWidth} = useResponsiveLayout(); - const [formDraft] = useOnyx(ONYXKEYS.FORMS.WORKSPACE_REPORT_FIELDS_FORM_DRAFT); + const [formDraft] = useOnyx(ONYXKEYS.FORMS.WORKSPACE_REPORT_FIELDS_FORM_DRAFT, {canBeMissing: true}); const {selectionMode} = useMobileSelectionMode(); const [selectedValues, setSelectedValues] = useState>({}); diff --git a/src/pages/workspace/tags/WorkspaceTagsPage.tsx b/src/pages/workspace/tags/WorkspaceTagsPage.tsx index 1a4858a546569..76587d5298462 100644 --- a/src/pages/workspace/tags/WorkspaceTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceTagsPage.tsx @@ -78,10 +78,10 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) { const policyID = route.params.policyID; const backTo = route.params.backTo; const policy = usePolicy(policyID); - const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`); + const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, {canBeMissing: true}); const {selectionMode} = useMobileSelectionMode(); const {environmentURL} = useEnvironment(); - const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policy?.id}`); + const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policy?.id}`, {canBeMissing: true}); const isSyncInProgress = isConnectionInProgress(connectionSyncProgress, policy); const hasSyncError = shouldShowSyncError(policy, isSyncInProgress); const isConnectedToAccounting = Object.keys(policy?.connections ?? {}).length > 0; diff --git a/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx b/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx index b686811eeeba0..7c2625142d778 100644 --- a/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx @@ -64,7 +64,7 @@ function WorkspaceViewTagsPage({route}: WorkspaceViewTagsProps) { const policyID = route.params.policyID; const backTo = route.params.backTo; const policy = usePolicy(policyID); - const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`); + const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, {canBeMissing: true}); const {selectionMode} = useMobileSelectionMode(); const currentTagListName = useMemo(() => getTagListName(policyTags, route.params.orderWeight), [policyTags, route.params.orderWeight]); const currentPolicyTag = policyTags?.[currentTagListName]; From 8bfb717847eeafb9b95310ec2221a000cacaec04 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Thu, 24 Apr 2025 14:14:43 +0200 Subject: [PATCH 11/17] Add onModalWillShow and onModalWillHide props to BaseModal, improve statusbar color switch --- src/components/Modal/BaseModal.tsx | 8 ++++++- src/components/Modal/index.tsx | 35 +++++++++++++++++++----------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/components/Modal/BaseModal.tsx b/src/components/Modal/BaseModal.tsx index 66742bcfa9262..0d0d96fb2062b 100644 --- a/src/components/Modal/BaseModal.tsx +++ b/src/components/Modal/BaseModal.tsx @@ -52,6 +52,8 @@ function BaseModal( innerContainerStyle = {}, outerStyle, onModalShow = () => {}, + onModalWillShow, + onModalWillHide, propagateSwipe, fullscreen = true, animationIn, @@ -269,7 +271,11 @@ function BaseModal( onModalShow={handleShowModal} propagateSwipe={propagateSwipe} onModalHide={hideModal} - onModalWillShow={saveFocusState} + onModalWillShow={() => { + saveFocusState(); + onModalWillShow?.(); + }} + onModalWillHide={onModalWillHide} onDismiss={handleDismissModal} onSwipeComplete={() => onClose?.()} swipeDirection={swipeDirection} diff --git a/src/components/Modal/index.tsx b/src/components/Modal/index.tsx index daa64070f14ad..09e79418a2622 100644 --- a/src/components/Modal/index.tsx +++ b/src/components/Modal/index.tsx @@ -21,7 +21,6 @@ function Modal({fullscreen = true, onModalHide = () => {}, type, onModalShow = ( }; const hideModal = () => { - setStatusBarColor(previousStatusBarColor); onModalHide(); if ((window.history.state as WindowState)?.shouldGoBack) { window.history.back(); @@ -33,6 +32,21 @@ function Modal({fullscreen = true, onModalHide = () => {}, type, onModalShow = ( }); const showModal = () => { + if (shouldHandleNavigationBack) { + window.history.pushState({shouldGoBack: true}, '', null); + window.addEventListener('popstate', handlePopStateRef.current); + } + onModalShow?.(); + }; + + useEffect( + () => () => { + window.removeEventListener('popstate', handlePopStateRef.current); + }, + [], + ); + + const onModalWillShow = () => { const statusBarColor = StatusBar.getBackgroundColor() ?? theme.appBG; const isFullScreenModal = @@ -46,20 +60,13 @@ function Modal({fullscreen = true, onModalHide = () => {}, type, onModalShow = ( // If it is a full screen modal then match it with appBG, otherwise we use the backdrop color setStatusBarColor(isFullScreenModal ? theme.appBG : StyleUtils.getThemeBackgroundColor(statusBarColor)); } - - if (shouldHandleNavigationBack) { - window.history.pushState({shouldGoBack: true}, '', null); - window.addEventListener('popstate', handlePopStateRef.current); - } - onModalShow?.(); + rest.onModalWillShow?.(); }; - useEffect( - () => () => { - window.removeEventListener('popstate', handlePopStateRef.current); - }, - [], - ); + const onModalWillHide = () => { + setStatusBarColor(previousStatusBarColor); + rest.onModalWillHide?.(); + }; return ( {}, type, onModalShow = ( {...rest} onModalHide={hideModal} onModalShow={showModal} + onModalWillShow={onModalWillShow} + onModalWillHide={onModalWillHide} avoidKeyboard={false} fullscreen={fullscreen} useNativeDriver={false} From e49e151c408a4cdb6b44e45761d842e3a88916aa Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Thu, 24 Apr 2025 20:04:56 +0200 Subject: [PATCH 12/17] Fix ConfirmModal animation when removing tags --- .../workspace/tags/WorkspaceTagsPage.tsx | 215 +++++++++--------- 1 file changed, 108 insertions(+), 107 deletions(-) diff --git a/src/pages/workspace/tags/WorkspaceTagsPage.tsx b/src/pages/workspace/tags/WorkspaceTagsPage.tsx index 8662db98f45e6..6dc0039b917da 100644 --- a/src/pages/workspace/tags/WorkspaceTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceTagsPage.tsx @@ -434,116 +434,117 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) { const selectionModeHeader = selectionMode?.isEnabled && shouldUseNarrowLayout; return ( - - + - { - if (selectionMode?.isEnabled) { - setSelectedTags({}); - turnOffMobileSelectionMode(); - return; - } - - if (backTo) { - Navigation.goBack(backTo); - return; - } - - goBackFromWorkspaceCentralScreen(policyID); - }} - shouldShowThreeDotsButton={!policy?.hasMultipleTagLists} - threeDotsMenuItems={threeDotsMenuItems} - threeDotsAnchorPosition={threeDotsAnchorPosition} + - {!shouldUseNarrowLayout && getHeaderButtons()} - - {shouldUseNarrowLayout && {getHeaderButtons()}} - setIsDeleteTagsConfirmModalVisible(false)} - title={translate(selectedTagsArray.length === 1 ? 'workspace.tags.deleteTag' : 'workspace.tags.deleteTags')} - prompt={translate(selectedTagsArray.length === 1 ? 'workspace.tags.deleteTagConfirmation' : 'workspace.tags.deleteTagsConfirmation')} - confirmText={translate('common.delete')} - cancelText={translate('common.cancel')} - danger - /> - {(!shouldUseNarrowLayout || !hasVisibleTags || isLoading) && getHeaderText()} - {isLoading && ( - - )} - {!hasVisibleTags && !isLoading && ( - - { + if (selectionMode?.isEnabled) { + setSelectedTags({}); + turnOffMobileSelectionMode(); + return; + } + + if (backTo) { + Navigation.goBack(backTo); + return; + } + + goBackFromWorkspaceCentralScreen(policyID); + }} + shouldShowThreeDotsButton={!policy?.hasMultipleTagLists} + threeDotsMenuItems={threeDotsMenuItems} + threeDotsAnchorPosition={threeDotsAnchorPosition} + > + {!shouldUseNarrowLayout && getHeaderButtons()} + + {shouldUseNarrowLayout && {getHeaderButtons()}} + {(!shouldUseNarrowLayout || !hasVisibleTags || isLoading) && getHeaderText()} + {isLoading && ( + - - )} - {hasVisibleTags && !isLoading && ( - item && toggleTag(item)} - sections={[{data: tagList, isDisabled: false}]} - onCheckboxPress={toggleTag} - onSelectRow={navigateToTagSettings} - shouldSingleExecuteRowSelect={!canSelectMultiple} - onSelectAll={toggleAllTags} - ListItem={TableListItem} - customListHeader={getCustomListHeader()} - shouldPreventDefaultFocusOnSelectRow={!canUseTouchScreen()} - listHeaderWrapperStyle={[styles.ph9, styles.pv3, styles.pb5]} - onDismissError={(item) => !isMultiLevelTags && clearPolicyTagErrors(policyID, item.value, 0)} - listHeaderContent={shouldUseNarrowLayout ? getHeaderText() : null} - showScrollIndicator={false} - addBottomSafeAreaPadding - /> - )} - - setIsOfflineModalVisible(false)} - title={translate('common.youAppearToBeOffline')} - prompt={translate('common.thisFeatureRequiresInternet')} - confirmText={translate('common.buttonConfirm')} - shouldShowCancelButton={false} - /> - setIsDownloadFailureModalVisible(false)} - secondOptionText={translate('common.buttonConfirm')} - isVisible={isDownloadFailureModalVisible} - onClose={() => setIsDownloadFailureModalVisible(false)} - /> - - + )} + {!hasVisibleTags && !isLoading && ( + + + + )} + {hasVisibleTags && !isLoading && ( + item && toggleTag(item)} + sections={[{data: tagList, isDisabled: false}]} + onCheckboxPress={toggleTag} + onSelectRow={navigateToTagSettings} + shouldSingleExecuteRowSelect={!canSelectMultiple} + onSelectAll={toggleAllTags} + ListItem={TableListItem} + customListHeader={getCustomListHeader()} + shouldPreventDefaultFocusOnSelectRow={!canUseTouchScreen()} + listHeaderWrapperStyle={[styles.ph9, styles.pv3, styles.pb5]} + onDismissError={(item) => !isMultiLevelTags && clearPolicyTagErrors(policyID, item.value, 0)} + listHeaderContent={shouldUseNarrowLayout ? getHeaderText() : null} + showScrollIndicator={false} + addBottomSafeAreaPadding + /> + )} + + + setIsOfflineModalVisible(false)} + title={translate('common.youAppearToBeOffline')} + prompt={translate('common.thisFeatureRequiresInternet')} + confirmText={translate('common.buttonConfirm')} + shouldShowCancelButton={false} + /> + setIsDownloadFailureModalVisible(false)} + secondOptionText={translate('common.buttonConfirm')} + isVisible={isDownloadFailureModalVisible} + onClose={() => setIsDownloadFailureModalVisible(false)} + /> + setIsDeleteTagsConfirmModalVisible(false)} + title={translate(selectedTagsArray.length === 1 ? 'workspace.tags.deleteTag' : 'workspace.tags.deleteTags')} + prompt={translate(selectedTagsArray.length === 1 ? 'workspace.tags.deleteTagConfirmation' : 'workspace.tags.deleteTagsConfirmation')} + confirmText={translate('common.delete')} + cancelText={translate('common.cancel')} + danger + /> + ); } From 96ed5729e28e0d8b9a65cc2f3da5ec6f1c7642d8 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Thu, 24 Apr 2025 20:19:22 +0200 Subject: [PATCH 13/17] Migrate TestToolsModal to new modal --- src/components/TestToolsModal.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/TestToolsModal.tsx b/src/components/TestToolsModal.tsx index 43743dc610149..f235934c08d97 100644 --- a/src/components/TestToolsModal.tsx +++ b/src/components/TestToolsModal.tsx @@ -38,16 +38,13 @@ function TestToolsModal() { const isAuthenticated = useIsAuthenticated(); const route = getRouteBasedOnAuthStatus(isAuthenticated, activeRoute); - if (!isTestToolsModalOpen) { - return null; - } - return ( Date: Thu, 24 Apr 2025 20:23:36 +0200 Subject: [PATCH 14/17] Fix lint --- src/components/TestToolsModal.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/TestToolsModal.tsx b/src/components/TestToolsModal.tsx index f235934c08d97..8bdfc71f6ccd8 100644 --- a/src/components/TestToolsModal.tsx +++ b/src/components/TestToolsModal.tsx @@ -28,8 +28,8 @@ const modalContentMaxHeightPercentage = 0.75; function TestToolsModal() { const {shouldUseNarrowLayout} = useResponsiveLayout(); - const [isTestToolsModalOpen = false] = useOnyx(ONYXKEYS.IS_TEST_TOOLS_MODAL_OPEN); - const [shouldStoreLogs = false] = useOnyx(ONYXKEYS.SHOULD_STORE_LOGS); + const [isTestToolsModalOpen = false] = useOnyx(ONYXKEYS.IS_TEST_TOOLS_MODAL_OPEN, {canBeMissing: true}); + const [shouldStoreLogs = false] = useOnyx(ONYXKEYS.SHOULD_STORE_LOGS, {canBeMissing: true}); const {windowWidth, windowHeight} = useWindowDimensions(); const StyleUtils = useStyleUtils(); const styles = useThemeStyles(); From 307ab571f48c56797e6ec748446fffea14442992 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Tue, 29 Apr 2025 09:59:13 +0200 Subject: [PATCH 15/17] Fix ts --- src/components/Modal/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Modal/index.tsx b/src/components/Modal/index.tsx index 119e6722577db..d861b7e57df52 100644 --- a/src/components/Modal/index.tsx +++ b/src/components/Modal/index.tsx @@ -67,7 +67,7 @@ function Modal({fullscreen = true, onModalHide = () => {}, type, onModalShow = ( type === CONST.MODAL.MODAL_TYPE.CENTERED || type === CONST.MODAL.MODAL_TYPE.CENTERED_UNSWIPEABLE || type === CONST.MODAL.MODAL_TYPE.RIGHT_DOCKED || - type === CONST.MODAL.MODAL_TYPE.CENTERED_SWIPABLE_TO_RIGHT; + type === CONST.MODAL.MODAL_TYPE.CENTERED_SWIPEABLE_TO_RIGHT; if (statusBarColor) { setPreviousStatusBarColor(statusBarColor); From f11c4933599e0bf25116cf416823dd9caa73248c Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Mon, 5 May 2025 11:58:59 +0200 Subject: [PATCH 16/17] Refactor LayoutAnimationConfig mock to return a functional component --- tests/perf-test/ReportActionCompose.perf-test.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/perf-test/ReportActionCompose.perf-test.tsx b/tests/perf-test/ReportActionCompose.perf-test.tsx index 1b6a8c4e19eda..2e4f3914a0d6f 100644 --- a/tests/perf-test/ReportActionCompose.perf-test.tsx +++ b/tests/perf-test/ReportActionCompose.perf-test.tsx @@ -21,7 +21,9 @@ jest.mock('@gorhom/portal'); jest.mock('react-native-reanimated', () => ({ ...jest.requireActual('react-native-reanimated/mock'), useAnimatedRef: jest.fn(), - LayoutAnimationConfig: jest.fn(), + LayoutAnimationConfig: () => { + return ({children}: {children: React.ReactNode}) => children; + }, })); jest.mock('../../src/libs/Navigation/Navigation', () => ({ From 664c03cdb4410b40d70e589fc5426c34c26f69a3 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Mon, 5 May 2025 11:59:15 +0200 Subject: [PATCH 17/17] Revert status bar changes --- src/components/Modal/BaseModal.tsx | 8 +------ src/components/Modal/index.tsx | 35 +++++++++++------------------- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/src/components/Modal/BaseModal.tsx b/src/components/Modal/BaseModal.tsx index 1576f17ad886f..fd44f593f189d 100644 --- a/src/components/Modal/BaseModal.tsx +++ b/src/components/Modal/BaseModal.tsx @@ -52,8 +52,6 @@ function BaseModal( innerContainerStyle = {}, outerStyle, onModalShow = () => {}, - onModalWillShow, - onModalWillHide, propagateSwipe, fullscreen = true, animationIn, @@ -271,11 +269,7 @@ function BaseModal( onModalShow={handleShowModal} propagateSwipe={propagateSwipe} onModalHide={hideModal} - onModalWillShow={() => { - saveFocusState(); - onModalWillShow?.(); - }} - onModalWillHide={onModalWillHide} + onModalWillShow={saveFocusState} onDismiss={handleDismissModal} onSwipeComplete={() => onClose?.()} swipeDirection={swipeDirection} diff --git a/src/components/Modal/index.tsx b/src/components/Modal/index.tsx index deca4d0901f1e..16907a590852a 100644 --- a/src/components/Modal/index.tsx +++ b/src/components/Modal/index.tsx @@ -21,6 +21,7 @@ function Modal({fullscreen = true, onModalHide = () => {}, type, onModalShow = ( }; const hideModal = () => { + setStatusBarColor(previousStatusBarColor); onModalHide(); if ((window.history.state as WindowState)?.shouldGoBack) { window.history.back(); @@ -32,21 +33,6 @@ function Modal({fullscreen = true, onModalHide = () => {}, type, onModalShow = ( }); const showModal = () => { - if (shouldHandleNavigationBack) { - window.history.pushState({shouldGoBack: true}, '', null); - window.addEventListener('popstate', handlePopStateRef.current); - } - onModalShow?.(); - }; - - useEffect( - () => () => { - window.removeEventListener('popstate', handlePopStateRef.current); - }, - [], - ); - - const onModalWillShow = () => { const statusBarColor = StatusBar.getBackgroundColor() ?? theme.appBG; const isFullScreenModal = @@ -60,22 +46,27 @@ function Modal({fullscreen = true, onModalHide = () => {}, type, onModalShow = ( // If it is a full screen modal then match it with appBG, otherwise we use the backdrop color setStatusBarColor(isFullScreenModal ? theme.appBG : StyleUtils.getThemeBackgroundColor(statusBarColor)); } - rest.onModalWillShow?.(); - }; - const onModalWillHide = () => { - setStatusBarColor(previousStatusBarColor); - rest.onModalWillHide?.(); + if (shouldHandleNavigationBack) { + window.history.pushState({shouldGoBack: true}, '', null); + window.addEventListener('popstate', handlePopStateRef.current); + } + onModalShow?.(); }; + useEffect( + () => () => { + window.removeEventListener('popstate', handlePopStateRef.current); + }, + [], + ); + return (