Skip to content

Commit 54e5655

Browse files
authored
Merge pull request Expensify#91015 from Expensify/claude-fixAgentDeleteBackNavigation
Fix back navigation after agent deletion
2 parents 5d184ee + 392b556 commit 54e5655

4 files changed

Lines changed: 59 additions & 8 deletions

File tree

src/libs/actions/Agent.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ function deleteAgent(accountID: number) {
282282
];
283283

284284
write(WRITE_COMMANDS.DELETE_AGENT, {agentAccountID: accountID}, {optimisticData, successData, failureData});
285-
Navigation.navigate(ROUTES.SETTINGS_AGENTS);
285+
Navigation.goBack(ROUTES.SETTINGS_AGENTS);
286286
}
287287

288288
export {

src/pages/settings/Agents/EditAgentPage.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {clearAgentAvatarUpdateError, clearAgentNameUpdateError, clearAgentPrompt
1717
import Navigation from '@libs/Navigation/Navigation';
1818
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
1919
import type {SettingsNavigatorParamList} from '@libs/Navigation/types';
20+
import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
2021
import CONST from '@src/CONST';
2122
import ONYXKEYS from '@src/ONYXKEYS';
2223
import ROUTES from '@src/ROUTES';
@@ -29,9 +30,11 @@ function EditAgentPage({route}: EditAgentPageProps) {
2930
const styles = useThemeStyles();
3031
const icons = useMemoizedLazyExpensifyIcons(['Trashcan']);
3132
const accountID = route.params.accountID;
32-
const [agent] = useOnyx(`${ONYXKEYS.COLLECTION.SHARED_NVP_AGENT_PROMPT}${accountID}`);
33-
const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {selector: (list) => list?.[accountID]});
33+
const [agent, agentMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.SHARED_NVP_AGENT_PROMPT}${accountID}`);
34+
const [personalDetails, personalDetailsMetadata] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {selector: (list) => list?.[accountID]});
3435
const {showConfirmModal} = useConfirmModal();
36+
const isOnyxLoaded = agentMetadata.status === 'loaded' && personalDetailsMetadata.status === 'loaded';
37+
const shouldShowNotFoundPage = isOnyxLoaded && !agent && !personalDetails;
3538

3639
const handleBackPress = () => Navigation.goBack();
3740
const handleEditAvatarPress = () => Navigation.navigate(ROUTES.SETTINGS_AGENTS_EDIT_AVATAR.getRoute(accountID));
@@ -44,13 +47,18 @@ function EditAgentPage({route}: EditAgentPageProps) {
4447
confirmText: translate('common.delete'),
4548
cancelText: translate('common.cancel'),
4649
danger: true,
50+
shouldHandleNavigationBack: false,
4751
});
4852
if (result.action !== ModalActions.CONFIRM) {
4953
return;
5054
}
5155
deleteAgent(accountID);
5256
};
5357

58+
if (shouldShowNotFoundPage) {
59+
return <NotFoundPage onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_AGENTS)} />;
60+
}
61+
5462
return (
5563
<ScreenWrapper
5664
testID={EditAgentPage.displayName}

tests/unit/AgentActionTest.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ import ONYXKEYS from '@src/ONYXKEYS';
88
import type {AnyOnyxUpdate} from '@src/types/onyx/Request';
99

1010
jest.mock('@libs/API');
11-
jest.mock('@libs/Navigation/Navigation', () => ({navigate: jest.fn()}));
11+
jest.mock('@libs/Navigation/Navigation', () => ({navigate: jest.fn(), goBack: jest.fn()}));
1212

1313
const mockWrite = jest.mocked(write);
14-
const mockNavigate = jest.mocked(Navigation.navigate);
14+
const mockGoBack = jest.mocked(Navigation.goBack);
1515

1616
function getWriteOptions(): {optimisticData: AnyOnyxUpdate[]; successData: AnyOnyxUpdate[]; failureData: AnyOnyxUpdate[]} {
1717
const options = mockWrite.mock.calls.at(0)?.at(2);
@@ -386,10 +386,10 @@ describe('deleteAgent', () => {
386386
expect((promptUpdate?.value as Record<string, unknown>)?.errors).toBeTruthy();
387387
});
388388

389-
it('calls Navigation.navigate after issuing the write', () => {
389+
it('calls Navigation.goBack after issuing the write', () => {
390390
deleteAgent(TEST_ACCOUNT_ID);
391391

392-
expect(mockNavigate).toHaveBeenCalledTimes(1);
392+
expect(mockGoBack).toHaveBeenCalledTimes(1);
393393
});
394394
});
395395

tests/unit/pages/settings/EditAgentPageTest.tsx

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,13 @@ jest.mock('@components/ReportActionAvatars', () => {
131131
return MockReportActionAvatars;
132132
});
133133

134+
jest.mock('@pages/ErrorPage/NotFoundPage', () => {
135+
function MockNotFoundPage() {
136+
return 'notFound.notHere';
137+
}
138+
return MockNotFoundPage;
139+
});
140+
134141
const mockUseOnyx = jest.mocked(useOnyx);
135142

136143
const TEST_ACCOUNT_ID = 12345;
@@ -144,7 +151,15 @@ const mockNavigation = {} as EditAgentPageNavigation;
144151
describe('EditAgentPage', () => {
145152
beforeEach(() => {
146153
jest.clearAllMocks();
147-
mockUseOnyx.mockReturnValue([undefined, {status: 'loaded'}]);
154+
mockUseOnyx.mockImplementation((key, options) => {
155+
if (key === ONYXKEYS.PERSONAL_DETAILS_LIST && options?.selector) {
156+
return [{displayName: 'Default Agent'}, {status: 'loaded'}];
157+
}
158+
if (typeof key === 'string' && key.startsWith(ONYXKEYS.COLLECTION.SHARED_NVP_AGENT_PROMPT)) {
159+
return [{prompt: 'Default prompt'}, {status: 'loaded'}];
160+
}
161+
return [undefined, {status: 'loaded'}];
162+
});
148163
});
149164

150165
it('renders agent name from personalDetails', () => {
@@ -229,4 +244,32 @@ describe('EditAgentPage', () => {
229244

230245
expect(JSON.stringify(toJSON())).toContain('agentsPage.error.updatePrompt');
231246
});
247+
248+
it('renders NotFoundPage when agent and personalDetails are both missing after Onyx is loaded', () => {
249+
mockUseOnyx.mockReturnValue([undefined, {status: 'loaded'}]);
250+
251+
const {toJSON} = render(
252+
<EditAgentPage
253+
route={mockRoute}
254+
navigation={mockNavigation}
255+
/>,
256+
);
257+
258+
const serialized = JSON.stringify(toJSON());
259+
expect(serialized).toContain('notFound.notHere');
260+
expect(serialized).not.toContain('editAgentPage.deleteAgent');
261+
});
262+
263+
it('does not render NotFoundPage while Onyx is still loading', () => {
264+
mockUseOnyx.mockReturnValue([undefined, {status: 'loading'}]);
265+
266+
const {toJSON} = render(
267+
<EditAgentPage
268+
route={mockRoute}
269+
navigation={mockNavigation}
270+
/>,
271+
);
272+
273+
expect(JSON.stringify(toJSON())).not.toContain('notFound.notHere');
274+
});
232275
});

0 commit comments

Comments
 (0)