From 1aae926944752d85ef64355cadc65b94eb0b9f1a Mon Sep 17 00:00:00 2001 From: dongmucat <1127093059@qq.com> Date: Fri, 27 Mar 2026 17:27:24 +0800 Subject: [PATCH] fix(web): improve network error message with i18n - Replace hardcoded 'Network error' with i18n key 'apiError.networkError' - Add dedicated handler for status 0 in handleApiError - Add test case for network error scenario Closes #160 --- web/src/api/client.ts | 2 +- web/src/shared/lib/api-error.test.ts | 10 ++++++++++ web/src/shared/lib/api-error.ts | 5 +++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/web/src/api/client.ts b/web/src/api/client.ts index 68f70fec..f28168b7 100644 --- a/web/src/api/client.ts +++ b/web/src/api/client.ts @@ -213,7 +213,7 @@ export async function fetchJson(input: RequestInfo | URL, init?: RequestWithT if (error instanceof DOMException && error.name === 'AbortError') { throw new ApiError('error.request.timeout', 408) } - throw new ApiError('Network error', 0) + throw new ApiError('apiError.networkError', 0) } finally { cleanup() } diff --git a/web/src/shared/lib/api-error.test.ts b/web/src/shared/lib/api-error.test.ts index 854c78c4..51ad23a8 100644 --- a/web/src/shared/lib/api-error.test.ts +++ b/web/src/shared/lib/api-error.test.ts @@ -53,4 +53,14 @@ describe('handleApiError', () => { expect(errorSpy).toHaveBeenLastCalledWith('Server said no') }) + + it('shows network error message for status 0', async () => { + const { ApiError, handleApiError } = await import('./api-error') + + handleApiError(new ApiError('apiError.networkError', 0)) + + expect(errorSpy).toHaveBeenCalled() + const lastCall = errorSpy.mock.calls[errorSpy.mock.calls.length - 1][0] + expect(lastCall).toMatch(/network|网络/) + }) }) diff --git a/web/src/shared/lib/api-error.ts b/web/src/shared/lib/api-error.ts index 0f772cc6..03efebca 100644 --- a/web/src/shared/lib/api-error.ts +++ b/web/src/shared/lib/api-error.ts @@ -52,6 +52,11 @@ export function handleApiError(error: unknown): void { const { status } = error + if (status === 0) { + toast.error(i18n.t('apiError.networkError')) + return + } + if (status === 401) { if (isAccountDisabledError(error)) { window.location.href = `/login?reason=${ACCOUNT_DISABLED_REASON}`