From 9328556c28a05eb31467018f7feb01a08b5e1205 Mon Sep 17 00:00:00 2001 From: Amirhossein Khalili Date: Mon, 21 Sep 2026 19:12:08 +0330 Subject: [PATCH] feat(frontend): add branded not-found page --- README.md | 1 + frontend/app/app.vue | 36 +---------------------- frontend/app/error.test.ts | 21 ++++++++++++++ frontend/app/error.vue | 55 ++++++++++++++++++++++++++++++++++++ frontend/app/pages/index.vue | 37 ++++++++++++++++++++++++ 5 files changed, 115 insertions(+), 35 deletions(-) create mode 100644 frontend/app/error.test.ts create mode 100644 frontend/app/error.vue create mode 100644 frontend/app/pages/index.vue diff --git a/README.md b/README.md index 6e514a0..bfc981e 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ Errors use the same `requestId` returned in the `X-Request-ID` header. See Swagg - The backend validates card numbers and refreshes ZarinHub access tokens automatically. - Every conversion attempt is audited in SQLite. - Card numbers and upstream responses are sanitized before storage; credentials and tokens are not persisted. +- Unknown frontend routes display a branded 404 page with a link back to the application. - SQLite data is stored in the `card_to_iban_data` Docker volume when using Compose. ## Tests diff --git a/frontend/app/app.vue b/frontend/app/app.vue index 6937d37..8f62b8b 100644 --- a/frontend/app/app.vue +++ b/frontend/app/app.vue @@ -1,37 +1,3 @@ - - diff --git a/frontend/app/error.test.ts b/frontend/app/error.test.ts new file mode 100644 index 0000000..5e206d5 --- /dev/null +++ b/frontend/app/error.test.ts @@ -0,0 +1,21 @@ +import { mount } from '@vue/test-utils' +import { describe, expect, it } from 'vitest' + +import ErrorPage from './error.vue' + +describe('ErrorPage', () => { + it('renders a branded not-found page with a way home', () => { + const wrapper = mount(ErrorPage, { + props: { + error: { + statusCode: 404, + statusMessage: 'Page not found', + }, + }, + }) + + expect(wrapper.get('h1').text()).toBe('صفحه پیدا نشد') + expect(wrapper.get('a').attributes('href')).toBe('/') + expect(wrapper.get('[role="img"]').attributes('aria-label')).toBe('زرین‌پال') + }) +}) diff --git a/frontend/app/error.vue b/frontend/app/error.vue new file mode 100644 index 0000000..9de0793 --- /dev/null +++ b/frontend/app/error.vue @@ -0,0 +1,55 @@ + + + diff --git a/frontend/app/pages/index.vue b/frontend/app/pages/index.vue new file mode 100644 index 0000000..6937d37 --- /dev/null +++ b/frontend/app/pages/index.vue @@ -0,0 +1,37 @@ + + +