Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OV-7: error handling #21

Merged
merged 4 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {
type Middleware,
isRejected,
isRejectedWithValue,
} from '@reduxjs/toolkit';
import { type ServerValidationErrorResponse } from 'shared';

import { toastService } from '../services/services.js';

const toastId = 'redux-store-error';

const errorMiddleware: Middleware = () => {
return (next) => (action) => {
let message: string = '';
if (isRejectedWithValue(action)) {
message += JSON.stringify(action.payload);
} else if (isRejected(action)) {
const error = action.error as ServerValidationErrorResponse;
message += `${error.message}\n`;
if (error.details) {
for (const errorDetail of error.details) {
message += `\t- ${errorDetail.message}\n`;
}
}
}

if (message !== '' && !toastService.isActive(toastId)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (message !== '' && !toastService.isActive(toastId)) {
if (message && !toastService.isActive(toastId)) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

toastService.error(message, toastId, 'An error occurred.');
}

return next(action);
};
};

export { errorMiddleware };
1 change: 1 addition & 0 deletions frontend/src/bundles/common/middlewares/middlewares.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { errorMiddleware } from './error-handling.middleware.js';
1 change: 1 addition & 0 deletions frontend/src/bundles/common/services/services.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { type ToastService, toastService } from './toast/toast.js';
92 changes: 92 additions & 0 deletions frontend/src/bundles/common/services/toast/toast.service.ts
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename it to notification.service.ts

Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { type createStandaloneToast } from '@chakra-ui/react';

type Constructor = {
toast: ReturnType<typeof createStandaloneToast>['toast'];
};

class ToastService {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

private toast: ReturnType<typeof createStandaloneToast>['toast'];

public constructor({ toast }: Constructor) {
this.toast = toast;
}

public warn = (message: string, toastId: string, title: string): void => {
this.toast({
id: toastId,
title: title,
description: message,
status: 'warning',
duration: 7000,
isClosable: true,
position: 'top-right',
variant: 'solid',
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are using the same properties for every method except for status.

Create a separate function for calling toast and just pass status as argument

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

};

public loading = (
message: string,
toastId: string,
title: string,
): void => {
this.toast({
id: toastId,
title: title,
description: message,
status: 'loading',
duration: 7000,
isClosable: true,
position: 'top-right',
variant: 'solid',
});
};

public error = (message: string, toastId: string, title: string): void => {
this.toast({
id: toastId,
title: title,
description: message,
status: 'error',
duration: 7000,
isClosable: true,
position: 'top-right',
variant: 'solid',
});
};

public success = (
message: string,
toastId: string,
title: string,
): void => {
this.toast({
id: toastId,
title: title,
description: message,
status: 'success',
duration: 7000,
isClosable: true,
position: 'top-right',
variant: 'solid',
});
};

public info = (message: string, toastId: string, title: string): void => {
this.toast({
id: toastId,
title: title,
description: message,
status: 'info',
duration: 7000,
isClosable: true,
position: 'top-right',
variant: 'solid',
});
};

public isActive = (toastId: string): boolean => {
return this.toast.isActive(toastId);
};
}

export { ToastService };
12 changes: 12 additions & 0 deletions frontend/src/bundles/common/services/toast/toast.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { createStandaloneToast } from '@chakra-ui/react';

import { theme } from '~/framework/theme/theme.js';

import { ToastService } from './toast.service.js';

const { toast } = createStandaloneToast({ theme: theme });

const toastService = new ToastService({ toast });

export { ToastService } from './toast.service.js';
export { toastService };
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to combine these 2 exports?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if I try to do so, I receive the next error:

Use export…from to re-export NotificationService.eslint unicorn/prefer-export-from

5 changes: 4 additions & 1 deletion frontend/src/framework/store/store.package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import { reducer as usersReducer } from '~/bundles/users/store/users.js';
import { userApi } from '~/bundles/users/users.js';
import { type Config } from '~/framework/config/config.js';

import { errorMiddleware } from '../../bundles/common/middlewares/error-handling.middleware.js';

type RootReducer = {
auth: ReturnType<typeof authReducer>;
users: ReturnType<typeof usersReducer>;
Expand Down Expand Up @@ -39,11 +41,12 @@ class Store {
users: usersReducer,
},
middleware: (getDefaultMiddleware) => {
return getDefaultMiddleware({
const middlewares = getDefaultMiddleware({
thunk: {
extraArgument: this.extraArguments,
},
});
return [...middlewares, errorMiddleware] as Tuple;
},
});
}
Expand Down
Loading