diff --git a/src/application/i18n/messages/en.json b/src/application/i18n/messages/en.json index e1b3baf2..5010264b 100644 --- a/src/application/i18n/messages/en.json +++ b/src/application/i18n/messages/en.json @@ -176,6 +176,7 @@ "noteSettings": "Note settings", "marketplace": "Marketplace", "addTool": "Add tool", + "error": "Error", "notFound": "Not found", "joinTeam": "Join", "authorization": "Authorize", diff --git a/src/application/router/routes.ts b/src/application/router/routes.ts index d242dbf4..1fe9147a 100644 --- a/src/application/router/routes.ts +++ b/src/application/router/routes.ts @@ -179,7 +179,6 @@ const routes: RouteRecordRaw[] = [ discardTabOnLeave: true, }, }, - /** * 404 page */ @@ -195,6 +194,22 @@ const routes: RouteRecordRaw[] = [ code: 404, }, }, + /** + * error page + */ + { + path: '/error/:code', + component: ErrorPage, + meta: { + layout: 'fullpage', + pageTitleI18n: 'pages.error', + discardTabOnLeave: true, + }, + props: route => ({ + code: route.params.code, + customMessage: route.query.message, + }), + }, ]; export default routes; diff --git a/src/application/services/useNote.ts b/src/application/services/useNote.ts index 938fbc0f..8afc5988 100644 --- a/src/application/services/useNote.ts +++ b/src/application/services/useNote.ts @@ -5,6 +5,7 @@ import type { NoteTool } from '@/domain/entities/Note'; import { useRouter, useRoute } from 'vue-router'; import type { NoteDraft } from '@/domain/entities/NoteDraft'; import type EditorTool from '@/domain/entities/EditorTool'; +import NotFoundError from '@/domain/entities/errors/NotFound'; import useHeader from './useHeader'; import { getTitle } from '@/infrastructure/utils/note'; @@ -166,12 +167,20 @@ export default function (options: UseNoteComposableOptions): UseNoteComposableSt /** * @todo try-catch domain errors */ - const response = await noteService.getNoteById(id); - - note.value = response.note; - canEdit.value = response.accessRights.canEdit; - noteTools.value = response.tools; - parentNote.value = response.parentNote; + try { + const response = await noteService.getNoteById(id); + + note.value = response.note; + canEdit.value = response.accessRights.canEdit; + noteTools.value = response.tools; + parentNote.value = response.parentNote; + } catch (error) { + if (error instanceof NotFoundError) { + void router.push(`/error/404`); + } else { + void router.push('/error/500'); + } + } } /** diff --git a/src/domain/entities/errors/ApiError.ts b/src/domain/entities/errors/ApiError.ts new file mode 100644 index 00000000..0efc2987 --- /dev/null +++ b/src/domain/entities/errors/ApiError.ts @@ -0,0 +1,16 @@ +import DomainError from './Base'; + +/** + * Domain error thrown when unknown error occurs + */ +export default class ApiError extends DomainError { + /** + * Constructor for ApiError error + * @param message - Error message + * @param statusCode - Error status code + */ + constructor(message: string, public statusCode: number) { + super(message); + this.name = 'ApiError'; + } +} diff --git a/src/infrastructure/transport/notes-api/index.ts b/src/infrastructure/transport/notes-api/index.ts index 175a5bc8..6df6ace2 100644 --- a/src/infrastructure/transport/notes-api/index.ts +++ b/src/infrastructure/transport/notes-api/index.ts @@ -5,6 +5,7 @@ import AuthorizableTransport from '@/infrastructure/transport/authorizable.trans import type JSONValue from '../types/JSONValue'; import UnauthorizedError from '@/domain/entities/errors/Unauthorized'; import NotFoundError from '@/domain/entities/errors/NotFound'; +import ApiError from '@/domain/entities/errors/ApiError'; import type { FilesDto } from '../types/FileDto'; /** @@ -53,7 +54,7 @@ export default class NotesApiTransport extends AuthorizableTransport { case 404: return new NotFoundError(errorText); default: - return new Error(errorText); + return new ApiError(errorText, status); } }, }); diff --git a/src/presentation/pages/Error.vue b/src/presentation/pages/Error.vue index ec704511..c22787e8 100644 --- a/src/presentation/pages/Error.vue +++ b/src/presentation/pages/Error.vue @@ -12,6 +12,12 @@