Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions apps/mobile/src/components/account/delete-account-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ export function DeleteAccountSection(): React.ReactNode {
Alert.alert(t('deleteAccountMismatch'));
return;
}
if (outcome.kind === 'unknown') {
Alert.alert(t('deleteUnknown'));
return;
}
if (outcome.kind === 'failed') {
Alert.alert(failureMessage(outcome.code));
return;
Expand Down
8 changes: 6 additions & 2 deletions apps/mobile/src/runtime/cloud/__tests__/deletion.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,12 +272,16 @@ describe('deleteAccount', () => {
expect(result).toEqual({ kind: 'pending', reference: 'ref-1' });
});

it('treats a thrown network error as failed — never assumes acceptance', async () => {
it('treats a thrown network error as unknown and reports the transport failure', async () => {
mocks.fetchDelete.mockRejectedValueOnce(new Error('offline'));

const result = await deleteAccount();

expect(result).toEqual({ kind: 'failed' });
expect(result).toEqual({ kind: 'unknown' });
expect(mocks.captureException).toHaveBeenCalledWith(
expect.any(Error),
expect.objectContaining({ tags: { account_deletion_stage: 'transport' } }),
);
});

it('treats an unparseable success response as pending rather than completed', async () => {
Expand Down
8 changes: 4 additions & 4 deletions apps/mobile/src/runtime/cloud/deletion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ export type AccountDeletionOutcome =
| { kind: 'apple-device-required' }
/** Browser re-authentication signed in a different Cloud account. */
| { kind: 'account-mismatch' }
/** The delete request failed before any state changed (network error, or
* a 409 pre-check) — the account is untouched. `code` is the server's biz
/** No HTTP response arrived, so the client cannot know whether deletion crossed PONR. */
| { kind: 'unknown' }
/** The server rejected the request before any state changed. `code` is the server's biz
Comment thread
lucas77778 marked this conversation as resolved.
* code when available (e.g. `ACCOUNT_DELETION_SOLE_ORGANIZATION_OWNER`),
* for copy that names the specific reason. */
| { kind: 'failed'; code?: string };
Expand Down Expand Up @@ -121,8 +122,7 @@ export async function deleteAccount(): Promise<AccountDeletionOutcome> {
});
} catch (error) {
reportFailure('transport', error);
// Without an HTTP response, never claim that the server accepted deletion.
return { kind: 'failed' };
return { kind: 'unknown' };
}

if (response.error) {
Expand Down
2 changes: 2 additions & 0 deletions packages/presentation/i18n/src/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1304,6 +1304,8 @@ export const en = {
'This account must be confirmed on a device that supports Sign in with Apple.',
deleteAccountMismatch:
'A different account was signed in. Sign in again with the account you want to delete.',
deleteUnknown:
'We couldn’t confirm whether your deletion request was received. Check your account status when you’re back online.',
Comment thread
lucas77778 marked this conversation as resolved.
deleteFailed: 'Could not delete your account. Please try again.',
deleteSoleOwner:
'You own a shared organization with other members. Transfer ownership before deleting your account.',
Expand Down
1 change: 1 addition & 0 deletions packages/presentation/i18n/src/locales/zh-cn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1264,6 +1264,7 @@ export const zhCN = {
deleteReauthenticationFailed: '无法确认身份,请重试。',
deleteAppleDeviceRequired: '此账号必须在支持「通过 Apple 登录」的设备上确认身份后删除。',
deleteAccountMismatch: '刚才登录的是另一个账号。请重新登录你想删除的账号。',
deleteUnknown: '无法确认删除请求是否已收到。请在网络恢复后检查账号状态。',
deleteFailed: '删除账号失败,请重试。',
deleteSoleOwner: '你是某个共享组织的唯一所有者。请先转移所有权,再删除账号。',
deleteEmergencyHold: '该账号暂不支持自助删除,请联系支持完成删除。',
Expand Down
Loading