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

Adding notification function for error and success messages #64

Merged
merged 2 commits into from
Apr 3, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
22 changes: 10 additions & 12 deletions src/features/History/History.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
import { Container, Group, Button } from '@mantine/core';
import { notifications } from '@mantine/notifications';
import dayjs from 'dayjs';
import { useState } from 'react';

import { DateRangePicker } from 'features/History/components/DateRangePicker/DateRangePicker';
import { Graph } from 'features/History/components/Graph/Graph';
import { useLazyGetSensorDataRangeQuery } from 'features/db/dbApi';

const handleError = () => {
notifications.show({
title: 'Oops!',
message: 'It seems something went wrong on our end. Please try again later',
color: 'red',
withBorder: true,
withCloseButton: false,
});
};
import { errorNotificationCurried } from 'utility/notificationUtils';

// TODO: Replace with actual arduino id from the store
const arduinoId = 0;
Expand All @@ -27,7 +17,15 @@ export const History = () => {
const [getData, { isLoading, data = [] }] = useLazyGetSensorDataRangeQuery();

const handleGetData = () =>
getData({ arduinoId, from, to }).unwrap().catch(handleError);
getData({ arduinoId, from, to })
.unwrap()
.catch(
errorNotificationCurried({
title: "Couldn't get sensor data",
message:
'It seems something went wrong on our end. Please try again later',
}),
);

return (
<Container size="xl">
Expand Down
34 changes: 16 additions & 18 deletions src/features/Settings/SettingsFormProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { zodResolver } from '@hookform/resolvers/zod';
import { Button, Group } from '@mantine/core';
import { notifications } from '@mantine/notifications';
import { PropsWithChildren, useEffect } from 'react';
import { useForm, FormProvider } from 'react-hook-form';

Expand All @@ -14,6 +13,10 @@ import {
useSetSettingsMutation,
} from 'features/db/dbApi';
import { useAppSelector } from 'store/hooks';
import {
errorNotificationCurried,
successNotificationCurried,
} from 'utility/notificationUtils';

export const SettingsFormProvider = ({ children }: PropsWithChildren) => {
const [getSettings] = useLazyGetSettingsQuery();
Expand All @@ -32,24 +35,19 @@ export const SettingsFormProvider = ({ children }: PropsWithChildren) => {
const onSubmit = (settings: Settings) => {
setSettings({ arduinoId: selectedDevice, settings })
.unwrap()
.then(() => {
notifications.show({
title: 'Congratulations!',
.then(
successNotificationCurried({
title: 'Settings saved',
message: 'Settings saved successfully!',
color: 'green',
withBorder: true,
withCloseButton: false,
});
})
.catch((error) => {
notifications.show({
title: 'Error saving settings:',
message: error,
color: 'red',
withBorder: true,
withCloseButton: false,
});
});
}),
)
.catch(
errorNotificationCurried({
title: 'Settings save error',
message:
'It seems something went wrong on our end. Please try again later',
}),
);
};

return (
Expand Down
47 changes: 16 additions & 31 deletions src/features/auth/pages/login/LoginForm.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { zodResolver } from '@hookform/resolvers/zod';
import { Paper, TextInput, PasswordInput, Button } from '@mantine/core';
import { notifications } from '@mantine/notifications';
import { FirebaseError } from 'firebase/app';
import { useForm, Controller, SubmitHandler } from 'react-hook-form';
import { useNavigate } from 'react-router-dom';

import { useLoginMutation } from 'features/auth/authApi';
import { LoginSchema } from 'features/auth/pages/validation';
import { routes } from 'router/routes';
import { errorNotification } from 'utility/notificationUtils';

interface ILoginForm {
email: string;
Expand All @@ -31,36 +30,22 @@ export const LoginForm = () => {
resolver: zodResolver(LoginSchema),
});

const onSubmit: SubmitHandler<ILoginForm> = async ({ email, password }) => {
try {
notifications.clean();
await login({ email, password }).unwrap();
navigate(routes.dashboard);
} catch (error) {
handleErrors(error);
}
};
const onSubmit: SubmitHandler<ILoginForm> = (props) => {
login(props)
.unwrap()
.then(() => {
navigate(routes.dashboard);
})
.catch((error) => {
const message =
error.code === 'auth/user-not-found'
? "User not found. Please check your credentials or sign up if you're a new user."
: error.code === 'auth/wrong-password'
? 'Incorrect username or password. Please try again.'
: 'It seems something went wrong on our end. Please try again later';

const handleErrors = (error: unknown) => {
console.error('authService.login error...', error);
let err =
'It seems something went wrong on our end. Please try again later';
if (error instanceof FirebaseError) {
if (
error.code === 'auth/user-not-found' ||
error.code === 'auth/wrong-password'
) {
err =
"User not found. Please check your credentials or sign up if you're new";
}
}
notifications.show({
title: 'Oops!',
message: err,
color: 'red',
withBorder: true,
withCloseButton: false,
});
errorNotification({ title: 'Login Error', message });
});
};

return (
Expand Down
19 changes: 8 additions & 11 deletions src/features/auth/pages/register/RegisterForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import { useForm, Controller, SubmitHandler } from 'react-hook-form';
import { useRegisterMutation } from 'features/auth/authApi';
import { RegisterSchema } from 'features/auth/pages/validation';
import { useSetUserDetailsMutation } from 'features/db/dbApi';
import {
errorNotification,
successNotification,
} from 'utility/notificationUtils';

interface IRegisterForm {
name: string;
Expand Down Expand Up @@ -52,23 +56,16 @@ export const RegisterForm = () => {
lastname,
username,
}).unwrap();
notifications.show({
title: 'Congratulations!',
successNotification({
title: "You're all set!",
message:
'Your account is all set up and you will now be redirected to the Login page',
color: 'green',
withBorder: true,
withCloseButton: false,
});
} catch (error) {
console.error('authService.register error...', error);
notifications.show({
title: 'Oops!',
errorNotification({
title: "We're sorry!",
message:
'It seems something went wrong on our end. Please try again later',
color: 'red',
withBorder: true,
withCloseButton: false,
});
}
};
Expand Down
26 changes: 12 additions & 14 deletions src/features/auth/pages/resetPassword/ResetPasswordForm.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { zodResolver } from '@hookform/resolvers/zod';
import { Paper, Button } from '@mantine/core';
import { notifications } from '@mantine/notifications';
import { useForm } from 'react-hook-form';

import { FormDevTools } from 'components/FormDevTools';
Expand All @@ -9,6 +8,10 @@ import { useResetPasswordMutation } from 'features/auth/authApi';
import { ResetPasswordSchema } from 'features/auth/pages/validation';
import { routes } from 'router/routes';
import { navigate } from 'router/utility/navigate';
import {
errorNotification,
successNotification,
} from 'utility/notificationUtils';

export type ResetPasswordFormData = {
email: string;
Expand All @@ -28,24 +31,19 @@ export const ResetPasswordForm = () => {
resetPassword({ email: data.email })
.unwrap()
.then(() => {
notifications.show({
title: 'Success',
successNotification({
title: 'Reset Password',
message: 'Please check your email to reset your password.',
color: 'green',
});
navigate(routes.login);
})
.catch((error) => {
let errorMessage = 'An error occurred, please try again.';
if (error?.code === 'auth/user-not-found') {
errorMessage =
'No user found with this email address. Please check and try again.';
}
notifications.show({
title: 'Error',
message: errorMessage,
color: 'red',
});
const message =
error?.code === 'auth/user-not-found'
? 'No user found with this email address. Please check and try again.'
: 'An error occurred, please try again.';

errorNotification({ title: 'Reset Password Error', message });
});
};

Expand Down
13 changes: 5 additions & 8 deletions src/features/layout/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
Title,
useMantineColorScheme,
} from '@mantine/core';
import { notifications } from '@mantine/notifications';
import { skipToken } from '@reduxjs/toolkit/query';
import {
IconGlassFullFilled,
Expand All @@ -23,6 +22,7 @@ import { useAuth } from 'features/auth/hooks/useAuth';
import { useGetUserDetailsQuery } from 'features/db/dbApi';
import { useSidebar } from 'features/layout/hooks/useSidebar';
import { getUserInitials } from 'features/layout/utils/getUserInitials';
import { errorNotificationCurried } from 'utility/notificationUtils';

export const Header = () => {
const [isOpen, toggleSidebar] = useSidebar();
Expand All @@ -40,16 +40,13 @@ export const Header = () => {
const handleLogout = () =>
logout()
.unwrap()
.catch(() => {
notifications.show({
.catch(
errorNotificationCurried({
title: 'Logout Error',
message:
'An error occurred while logging out. Please try again later.',
color: 'red',
withBorder: true,
withCloseButton: true,
});
});
}),
);

return (
<Group gap="xs" px="md" h="100%" justify="space-between">
Expand Down
53 changes: 53 additions & 0 deletions src/utility/notificationUtils.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { showNotification } from '@mantine/notifications';
import { IconCheck, IconX } from '@tabler/icons-react';

type NotificationOptions = {
title?: string;
message?: string;
};

interface ErrorNotificationProps extends NotificationOptions {
error?: unknown;
}

const genericErrorMessage = 'An error occurred. Please try again later.';
const genericSuccessMessage = 'Everything went well.';

const parseErrorMessage = (error: unknown) =>
error instanceof Error
? error.message
: typeof error === 'string'
? error
: genericErrorMessage;

export const errorNotification = ({
title = 'Error occurred',
message,
error,
}: ErrorNotificationProps) => {
showNotification({
title,
message: message ?? parseErrorMessage(error),
icon: <IconX size="1.1rem" />,
color: 'red',
});
};

export const errorNotificationCurried =
(props?: NotificationOptions) => (error?: unknown) => {
errorNotification({ ...props, error });
};

export const successNotification = (props?: NotificationOptions) => {
showNotification({
title: props?.title ?? 'Success',
message: props?.message ?? genericSuccessMessage,
icon: <IconCheck size="1.1rem" />,
color: 'green',
});
};

export const successNotificationCurried =
(props?: NotificationOptions) => () => {
successNotification(props);
};