diff --git a/apps/mobile/src/components/account/delete-account-section.tsx b/apps/mobile/src/components/account/delete-account-section.tsx index 12a360f0..aee324d1 100644 --- a/apps/mobile/src/components/account/delete-account-section.tsx +++ b/apps/mobile/src/components/account/delete-account-section.tsx @@ -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; diff --git a/apps/mobile/src/runtime/cloud/__tests__/deletion.test.ts b/apps/mobile/src/runtime/cloud/__tests__/deletion.test.ts index 71367b81..efe788ef 100644 --- a/apps/mobile/src/runtime/cloud/__tests__/deletion.test.ts +++ b/apps/mobile/src/runtime/cloud/__tests__/deletion.test.ts @@ -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 () => { diff --git a/apps/mobile/src/runtime/cloud/deletion.ts b/apps/mobile/src/runtime/cloud/deletion.ts index 98131a69..dd5d8e00 100644 --- a/apps/mobile/src/runtime/cloud/deletion.ts +++ b/apps/mobile/src/runtime/cloud/deletion.ts @@ -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 * code when available (e.g. `ACCOUNT_DELETION_SOLE_ORGANIZATION_OWNER`), * for copy that names the specific reason. */ | { kind: 'failed'; code?: string }; @@ -121,8 +122,7 @@ export async function deleteAccount(): Promise { }); } 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) { diff --git a/packages/presentation/i18n/src/locales/en.ts b/packages/presentation/i18n/src/locales/en.ts index abb19a54..02a18174 100644 --- a/packages/presentation/i18n/src/locales/en.ts +++ b/packages/presentation/i18n/src/locales/en.ts @@ -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.', deleteFailed: 'Could not delete your account. Please try again.', deleteSoleOwner: 'You own a shared organization with other members. Transfer ownership before deleting your account.', diff --git a/packages/presentation/i18n/src/locales/zh-cn.ts b/packages/presentation/i18n/src/locales/zh-cn.ts index aca53670..68d11d11 100644 --- a/packages/presentation/i18n/src/locales/zh-cn.ts +++ b/packages/presentation/i18n/src/locales/zh-cn.ts @@ -1264,6 +1264,7 @@ export const zhCN = { deleteReauthenticationFailed: '无法确认身份,请重试。', deleteAppleDeviceRequired: '此账号必须在支持「通过 Apple 登录」的设备上确认身份后删除。', deleteAccountMismatch: '刚才登录的是另一个账号。请重新登录你想删除的账号。', + deleteUnknown: '无法确认删除请求是否已收到。请在网络恢复后检查账号状态。', deleteFailed: '删除账号失败,请重试。', deleteSoleOwner: '你是某个共享组织的唯一所有者。请先转移所有权,再删除账号。', deleteEmergencyHold: '该账号暂不支持自助删除,请联系支持完成删除。',