Skip to content

Commit cc3f109

Browse files
authored
Merge pull request codex-team#277 from codex-team/fix/redirect-when-note-is-not-found
fix: Redirect to 404 Page When Note is Not Found
2 parents 8296cff + ae9a39b commit cc3f109

10 files changed

Lines changed: 118 additions & 20 deletions

File tree

src/application/i18n/messages/en.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,16 @@
105105
"title": "Recents",
106106
"authText": "You are not logged in, log in to see your recent notes"
107107
},
108+
"error": {
109+
"401": "Unauthorized",
110+
"404": "Not found",
111+
"403": "Forbidden",
112+
"500": "Internal server error"
113+
},
108114
"errors": {
115+
"401": "You must be authenticated to access this resource",
109116
"404": "Page not found",
117+
"403": "Access Denied",
110118
"500": "Unknown error happened",
111119
"default": "Something went wrong"
112120
},
@@ -176,6 +184,7 @@
176184
"noteSettings": "Note settings",
177185
"marketplace": "Marketplace",
178186
"addTool": "Add tool",
187+
"error": "Oops! Something went wrong",
179188
"notFound": "Not found",
180189
"joinTeam": "Join",
181190
"authorization": "Authorize",

src/application/router/routes.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,6 @@ const routes: RouteRecordRaw[] = [
179179
discardTabOnLeave: true,
180180
},
181181
},
182-
183182
/**
184183
* 404 page
185184
*/
@@ -195,6 +194,21 @@ const routes: RouteRecordRaw[] = [
195194
code: 404,
196195
},
197196
},
197+
/**
198+
* error page
199+
*/
200+
{
201+
path: '/error/:code',
202+
component: ErrorPage,
203+
meta: {
204+
layout: 'fullpage',
205+
pageTitleI18n: 'pages.error',
206+
discardTabOnLeave: true,
207+
},
208+
props: route => ({
209+
code: route.params.code,
210+
}),
211+
},
198212
];
199213

200214
export default routes;

src/application/services/useNote.ts

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { NoteTool } from '@/domain/entities/Note';
55
import { useRouter, useRoute } from 'vue-router';
66
import type { NoteDraft } from '@/domain/entities/NoteDraft';
77
import type EditorTool from '@/domain/entities/EditorTool';
8+
import DomainError from '@/domain/entities/errors/Base';
89
import useNavbar from './useNavbar';
910
import { getTitle } from '@/infrastructure/utils/note';
1011

@@ -98,7 +99,7 @@ interface UseNoteComposableOptions {
9899
* @param options - note service options
99100
*/
100101
export default function (options: UseNoteComposableOptions): UseNoteComposableState {
101-
const { patchOpenedPageByUrl } = useNavbar();
102+
const { patchOpenedPageByUrl, deleteOpenedPageByUrl } = useNavbar();
102103
/**
103104
* Current note identifier
104105
*/
@@ -163,15 +164,21 @@ export default function (options: UseNoteComposableOptions): UseNoteComposableSt
163164
* @param id - Note identifier got from composable argument
164165
*/
165166
async function load(id: NoteId): Promise<void> {
166-
/**
167-
* @todo try-catch domain errors
168-
*/
169-
const response = await noteService.getNoteById(id);
170-
171-
note.value = response.note;
172-
canEdit.value = response.accessRights.canEdit;
173-
noteTools.value = response.tools;
174-
parentNote.value = response.parentNote;
167+
try {
168+
const response = await noteService.getNoteById(id);
169+
170+
note.value = response.note;
171+
canEdit.value = response.accessRights.canEdit;
172+
noteTools.value = response.tools;
173+
parentNote.value = response.parentNote;
174+
} catch (error) {
175+
deleteOpenedPageByUrl(route.path);
176+
if (error instanceof DomainError) {
177+
void router.push(`/error/${error.statusCode}`);
178+
} else {
179+
void router.push('/error/500');
180+
}
181+
}
175182
}
176183

177184
/**

src/domain/entities/errors/Base.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,16 @@
22
* Domain Error — own class describing exceptions in our business-logic.
33
* For example, when user is not authorized to perform some action.
44
*/
5-
export default class DomainError extends Error {}
5+
export default class DomainError extends Error {
6+
public statusCode?: number;
7+
/**
8+
* Constructor for Domain error
9+
* @param message - Error message
10+
* @param statusCode - Status code
11+
*/
12+
constructor(message: string, statusCode?: number) {
13+
super(message);
14+
this.name = 'DomainError';
15+
this.statusCode = statusCode;
16+
}
17+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import DomainError from './Base';
2+
3+
/**
4+
* Domain error thrown when user does not have permission
5+
*/
6+
export default class ForbiddenError extends DomainError {
7+
/**
8+
* Constructor for NotFound error
9+
* @param message - Error message
10+
* @param statusCode - Error status code
11+
*/
12+
constructor(message: string = 'Permission denied', statusCode: number = 403) {
13+
super(message, statusCode);
14+
this.name = 'ForbiddenError';
15+
}
16+
};

src/domain/entities/errors/NotFound.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ export default class NotFoundError extends DomainError {
77
/**
88
* Constructor for NotFound error
99
* @param message - Error message
10+
* @param statusCode - Error status code
1011
*/
11-
constructor(message: string = 'NotFound') {
12-
super(message);
12+
constructor(message: string = 'NotFound', statusCode: number = 404) {
13+
super(message, statusCode);
1314
this.name = 'NotFoundError';
1415
}
1516
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import DomainError from './Base';
2+
3+
/**
4+
* Domain error thrown when unknown error occurs
5+
*/
6+
export default class ResourceUnavailableError extends DomainError {
7+
/**
8+
* Constructor for ResourceUnavailableError error
9+
* @param message - Error message
10+
* @param statusCode - Error status code
11+
*/
12+
constructor(message: string = 'Internal server error', statusCode: number = 500) {
13+
super(message, statusCode);
14+
this.name = 'ResourceUnavailableError';
15+
}
16+
}
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import DomainError from './Base';
22

33
/**
4-
* Domain error thrown when user is not authorized to perform some action
4+
* Domain error thrown when user is not authenticated
55
*/
66
export default class UnauthorizedError extends DomainError {
77
/**
88
* Constructor for unauthorized error
99
* @param message - Error message
10+
* @param statusCode - Error status code
1011
*/
11-
constructor(message: string = 'Unauthorized') {
12-
super(message);
12+
constructor(message: string = 'Unauthorized', statusCode: number = 401) {
13+
super(message, statusCode);
1314
this.name = 'UnauthorizedError';
1415
}
1516
}

src/infrastructure/transport/notes-api/index.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import AuthorizableTransport from '@/infrastructure/transport/authorizable.trans
55
import type JSONValue from '../types/JSONValue';
66
import UnauthorizedError from '@/domain/entities/errors/Unauthorized';
77
import NotFoundError from '@/domain/entities/errors/NotFound';
8+
import ResourceUnavailableError from '@/domain/entities/errors/ResourceUnavailableError';
9+
import ForbiddenError from '@/domain/entities/errors/Forbidden';
810
import type { FilesDto } from '../types/FileDto';
911

1012
/**
@@ -48,12 +50,15 @@ export default class NotesApiTransport extends AuthorizableTransport {
4850
*/
4951
switch (status) {
5052
case 401:
53+
return new UnauthorizedError(errorText, status);
5154
case 403:
52-
return new UnauthorizedError(errorText);
55+
return new ForbiddenError(errorText, status);
5356
case 404:
54-
return new NotFoundError(errorText);
57+
return new NotFoundError(errorText, status);
58+
case 406:
59+
return new NotFoundError(errorText, status);
5560
default:
56-
return new Error(errorText);
61+
return new ResourceUnavailableError(errorText, 500);
5762
}
5863
},
5964
});

src/presentation/pages/Error.vue

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@
1212
<script setup lang="ts">
1313
import { computed } from 'vue';
1414
import { useI18n } from 'vue-i18n';
15+
import { useHead } from 'unhead';
16+
import { useRoute } from 'vue-router';
17+
import useNavbar from '@/application/services/useNavbar';
18+
19+
const route = useRoute();
20+
const { patchOpenedPageByUrl } = useNavbar();
1521
1622
const { t, te } = useI18n();
1723
@@ -44,6 +50,17 @@ const message = computed(() => {
4450
4551
return t('errors.default');
4652
});
53+
54+
useHead({
55+
title: t(`pages.error`),
56+
});
57+
58+
const openPageInfo = {
59+
title: te(`error.${props.code}`) ? t(`error.${props.code}`) : t(`pages.error`),
60+
url: route.path,
61+
};
62+
63+
patchOpenedPageByUrl(route.path, openPageInfo);
4764
</script>
4865

4966
<style lang="postcss" module>

0 commit comments

Comments
 (0)