Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
3881c58
fix: refactor modals
truph01 Jan 14, 2026
37299db
Merge branch 'Expensify:main' into fix/76693-part-1
truph01 Jan 15, 2026
750397e
fix: use async await
truph01 Jan 15, 2026
4278481
fix: lint
truph01 Jan 15, 2026
40fcf95
fix: lint
truph01 Jan 15, 2026
8988207
fix: lint
truph01 Jan 15, 2026
b0d82cf
fix: conflict
truph01 Jan 21, 2026
ae4f550
fix: refactor CardSection
truph01 Jan 22, 2026
aff60e6
fix: lint
truph01 Jan 22, 2026
d6d1ef0
fix: conflict
truph01 Jan 22, 2026
5825911
fix: conflicts
truph01 Jan 22, 2026
5be6d47
Merge branch 'Expensify:main' into fix/76693-part-1
truph01 Jan 26, 2026
1b80676
fix: remove IIFE
truph01 Jan 26, 2026
0411398
fix: remove manual memoization
truph01 Jan 26, 2026
143905c
Merge branch 'Expensify:main' into fix/76693-part-1
truph01 Jan 29, 2026
800b4e6
fix: wrong button color
truph01 Jan 29, 2026
01da2b0
Merge branch 'Expensify:main' into fix/76693-part-1
truph01 Feb 1, 2026
1babb55
fix: navigation issue when hiding modal in CardSection
truph01 Feb 1, 2026
412a566
fix: revert un-related change
truph01 Feb 1, 2026
73e5dc8
fix: conflict
truph01 Feb 9, 2026
5a96d85
fix: conflict
truph01 Feb 9, 2026
5572667
fix: lint
truph01 Feb 9, 2026
bc2a2ab
fix: lint
truph01 Feb 9, 2026
2cc52be
fix: conflicts
truph01 Feb 17, 2026
7d6f658
fix: conflicts
truph01 Feb 17, 2026
dcc7dd2
fix: conflicts
truph01 Feb 22, 2026
23a0636
fix: conflicts
truph01 Feb 22, 2026
0e3f689
fix: conflicts
truph01 Mar 2, 2026
81a75c8
fix: conflicts
truph01 Mar 2, 2026
f6aced9
fix: conflicts
truph01 Mar 2, 2026
426c3a6
fix: conflicts
truph01 Mar 2, 2026
b67d455
fix: conflicts
truph01 Mar 2, 2026
d7a5278
fix: merge main
truph01 Mar 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 23 additions & 29 deletions src/pages/settings/Security/CloseAccountPage.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import {Str} from 'expensify-common';
import React, {useEffect, useState} from 'react';
import React, {useEffect} from 'react';
import {View} from 'react-native';
import ConfirmModal from '@components/ConfirmModal';
import DelegateNoAccessWrapper from '@components/DelegateNoAccessWrapper';
import FormProvider from '@components/Form/FormProvider';
import InputWrapper from '@components/Form/InputWrapper';
import type {FormInputErrors, FormOnyxValues} from '@components/Form/types';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import {ModalActions} from '@components/Modal/Global/ModalContext';
import ScreenWrapper from '@components/ScreenWrapper';
import Text from '@components/Text';
import TextInput from '@components/TextInput';
import useConfirmModal from '@hooks/useConfirmModal';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import useThemeStyles from '@hooks/useThemeStyles';
Expand All @@ -30,27 +31,32 @@ function CloseAccountPage() {
const styles = useThemeStyles();
const {translate, formatPhoneNumber} = useLocalize();

const [isConfirmModalVisible, setConfirmModalVisibility] = useState(false);
const [reasonForLeaving, setReasonForLeaving] = useState('');
const {showConfirmModal} = useConfirmModal();
const showCloseAccountWarningModal = () => {
return showConfirmModal({
title: translate('closeAccountPage.closeAccountWarning'),
prompt: translate('closeAccountPage.closeAccountPermanentlyDeleteData'),
confirmText: translate('common.yesContinue'),
cancelText: translate('common.cancel'),
shouldShowCancelButton: true,
danger: true,
shouldDisableConfirmButtonWhenOffline: true,
});
};

// If you are new to hooks this might look weird but basically it is something that only runs when the component unmounts
// nothing runs on mount and we pass empty dependencies to prevent this from running on every re-render.
// TODO: We should refactor this so that the data in instead passed directly as a prop instead of "side loading" the data
// here, we left this as is during refactor to limit the breaking changes.
useEffect(() => () => clearError(), []);

const hideConfirmModal = () => {
setConfirmModalVisibility(false);
};

const onConfirm = () => {
closeAccount(reasonForLeaving);
hideConfirmModal();
};

const showConfirmModal = (values: FormOnyxValues<typeof ONYXKEYS.FORMS.CLOSE_ACCOUNT_FORM>) => {
setConfirmModalVisibility(true);
setReasonForLeaving(values.reasonForLeaving);
const onSubmit = (values: FormOnyxValues<typeof ONYXKEYS.FORMS.CLOSE_ACCOUNT_FORM>) => {
showCloseAccountWarningModal().then((result) => {
if (result.action !== ModalActions.CONFIRM) {
return;
}
closeAccount(values.reasonForLeaving);
});
};

const userEmailOrPhone = session?.email ? formatPhoneNumber(session.email) : null;
Expand Down Expand Up @@ -96,7 +102,7 @@ function CloseAccountPage() {
<FormProvider
formID={ONYXKEYS.FORMS.CLOSE_ACCOUNT_FORM}
validate={validate}
onSubmit={showConfirmModal}
onSubmit={onSubmit}
submitButtonText={translate('closeAccountPage.closeAccount')}
style={[styles.flexGrow1, styles.mh5]}
isSubmitActionDangerous
Expand Down Expand Up @@ -132,18 +138,6 @@ function CloseAccountPage() {
inputMode={userEmailOrPhone && Str.isValidEmail(userEmailOrPhone) ? CONST.INPUT_MODE.EMAIL : CONST.INPUT_MODE.TEXT}
forwardedFSClass={CONST.FULLSTORY.CLASS.UNMASK}
/>
<ConfirmModal
danger
title={translate('closeAccountPage.closeAccountWarning')}
onConfirm={onConfirm}
onCancel={hideConfirmModal}
isVisible={isConfirmModalVisible}
prompt={translate('closeAccountPage.closeAccountPermanentlyDeleteData')}
confirmText={translate('common.yesContinue')}
cancelText={translate('common.cancel')}
shouldDisableConfirmButtonWhenOffline
shouldShowCancelButton
/>
</View>
</FormProvider>
</DelegateNoAccessWrapper>
Expand Down
52 changes: 26 additions & 26 deletions src/pages/settings/Security/SecuritySettingsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import React, {useCallback, useEffect, useLayoutEffect, useMemo, useRef, useStat
import type {RefObject} from 'react';
import {Dimensions, View} from 'react-native';
import type {GestureResponderEvent, StyleProp, ViewStyle} from 'react-native';
import ConfirmModal from '@components/ConfirmModal';
import {useDelegateNoAccessActions, useDelegateNoAccessState} from '@components/DelegateNoAccessModalProvider';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import {useLockedAccountActions, useLockedAccountState} from '@components/LockedAccountModalProvider';
import MenuItem from '@components/MenuItem';
import type {MenuItemProps} from '@components/MenuItem';
import MenuItemList from '@components/MenuItemList';
import {ModalActions} from '@components/Modal/Global/ModalContext';
import {usePersonalDetails} from '@components/OnyxListItemProvider';
import PopoverMenu from '@components/PopoverMenu';
import type {PopoverMenuItem} from '@components/PopoverMenu';
Expand All @@ -18,6 +18,7 @@ import ScrollView from '@components/ScrollView';
import Section from '@components/Section';
import Text from '@components/Text';
import TextLink from '@components/TextLink';
import useConfirmModal from '@hooks/useConfirmModal';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import {useMemoizedLazyExpensifyIcons, useMemoizedLazyIllustrations} from '@hooks/useLazyAsset';
import useLocalize from '@hooks/useLocalize';
Expand Down Expand Up @@ -83,10 +84,21 @@ function SecuritySettingsPage() {
const delegateButtonRef = useRef<HTMLDivElement | null>(null);

const [shouldShowDelegatePopoverMenu, setShouldShowDelegatePopoverMenu] = useState(false);
const [shouldShowRemoveDelegateModal, setShouldShowRemoveDelegateModal] = useState(false);
const [selectedDelegate, setSelectedDelegate] = useState<Delegate | undefined>();
const [selectedEmail, setSelectedEmail] = useState<string | undefined>();

const {showConfirmModal} = useConfirmModal();
const showRemoveCopilotModal = useCallback(() => {
return showConfirmModal({
title: translate('delegate.removeCopilot'),
prompt: translate('delegate.removeCopilotConfirmation'),
confirmText: translate('delegate.removeCopilot'),
cancelText: translate('common.cancel'),
shouldShowCancelButton: true,
danger: true,
});
}, [showConfirmModal, translate]);

const errorFields = account?.delegatedAccess?.errorFields ?? {};

const [anchorPosition, setAnchorPosition] = useState<AnchorPosition>({
Expand Down Expand Up @@ -372,8 +384,19 @@ function SecuritySettingsPage() {
}
modalClose(() => {
setShouldShowDelegatePopoverMenu(false);
setShouldShowRemoveDelegateModal(true);
setSelectedEmail(undefined);
showRemoveCopilotModal().then((result) => {
if (result.action === ModalActions.CLOSE) {
setSelectedDelegate(undefined);
} else {
if (isActingAsDelegate) {
showDelegateNoAccessModal();
return;
}
removeDelegate({email: selectedDelegate?.email ?? '', delegatedAccess: account?.delegatedAccess});
setSelectedDelegate(undefined);
}
});
});
},
},
Expand Down Expand Up @@ -492,29 +515,6 @@ function SecuritySettingsPage() {
setSelectedEmail(undefined);
}}
/>
<ConfirmModal
isVisible={shouldShowRemoveDelegateModal}
title={translate('delegate.removeCopilot')}
prompt={translate('delegate.removeCopilotConfirmation')}
danger
onConfirm={() => {
if (isActingAsDelegate) {
setShouldShowRemoveDelegateModal(false);
showDelegateNoAccessModal();
return;
}
removeDelegate({email: selectedDelegate?.email ?? '', delegatedAccess: account?.delegatedAccess});
setShouldShowRemoveDelegateModal(false);
setSelectedDelegate(undefined);
}}
onCancel={() => {
setShouldShowRemoveDelegateModal(false);
setSelectedDelegate(undefined);
}}
confirmText={translate('delegate.removeCopilot')}
cancelText={translate('common.cancel')}
shouldShowCancelButton
/>
</View>
</ScrollView>
</>
Expand Down
Loading
Loading