From 46f925663e595fa8dd87f7aa15a0061abcfae3d7 Mon Sep 17 00:00:00 2001 From: Michael Hunteman Date: Mon, 2 Sep 2024 16:27:12 -0700 Subject: Add ui error messages --- client/src/components/AdminLogin.tsx | 41 +++++++++++++++++++++++++++++++----- client/src/components/GuestLogin.tsx | 41 +++++++++++++++++++++++++++++++----- client/src/components/RsvpForm.tsx | 27 +++++++++++++----------- client/src/error.ts | 11 ++++++++++ client/src/models.ts | 9 ++++++++ 5 files changed, 107 insertions(+), 22 deletions(-) create mode 100644 client/src/error.ts (limited to 'client') diff --git a/client/src/components/AdminLogin.tsx b/client/src/components/AdminLogin.tsx index 4f53566..4271d60 100644 --- a/client/src/components/AdminLogin.tsx +++ b/client/src/components/AdminLogin.tsx @@ -1,16 +1,38 @@ -import React from 'react'; +import React, { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { useDispatch } from 'react-redux'; -import { Button, Paper, TextField, Typography } from '@mui/material'; +import { + Alert, + Button, + Paper, + Snackbar, + TextField, + Typography, +} from '@mui/material'; import { useForm } from 'react-hook-form'; import { setAdmin } from '../slices/auth/adminSlice'; import { useLoginAdminMutation } from '../slices/api/adminSlice'; -import type { Credentials } from '../models'; +import type { Credentials, StatusProps } from '../models'; +import { isFetchBaseQueryError } from '../error'; +import type { Data } from '../error'; + +const Status = ({ error, setOpen }: StatusProps) => { + return isFetchBaseQueryError(error) ? ( + setOpen(false)}> + {(error.data as Data).message} + + ) : ( + setOpen(false)}> + Admin login failed + + ); +}; function GuestLogin() { const dispatch = useDispatch(); const navigate = useNavigate(); - const [login] = useLoginAdminMutation(); + const [login, { isLoading, error }] = useLoginAdminMutation(); + const [open, setOpen] = useState(false); const { register, @@ -28,7 +50,7 @@ function GuestLogin() { dispatch(setAdmin(await login(data).unwrap())); navigate('/dashboard'); } catch (e) { - console.log(e); + setOpen(true); } }; @@ -83,6 +105,15 @@ function GuestLogin() { Log in + setOpen(false)} + autoHideDuration={5000} + > +
+ +
+
); } diff --git a/client/src/components/GuestLogin.tsx b/client/src/components/GuestLogin.tsx index f42c1d6..acf229f 100644 --- a/client/src/components/GuestLogin.tsx +++ b/client/src/components/GuestLogin.tsx @@ -1,16 +1,38 @@ -import React from 'react'; +import React, { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { useDispatch } from 'react-redux'; -import { Button, Paper, TextField, Typography } from '@mui/material'; +import { + Alert, + Button, + Paper, + Snackbar, + TextField, + Typography, +} from '@mui/material'; import { useForm } from 'react-hook-form'; import { setGuest } from '../slices/auth/guestSlice'; import { useLoginGuestMutation } from '../slices/api/guestSlice'; -import type { Name } from '../models'; +import type { Name, StatusProps } from '../models'; +import { isFetchBaseQueryError } from '../error'; +import type { Data } from '../error'; + +const Status = ({ error, setOpen }: StatusProps) => { + return isFetchBaseQueryError(error) ? ( + setOpen(false)}> + {(error.data as Data).message} + + ) : ( + setOpen(false)}> + Guest login failed + + ); +}; function GuestLogin() { const dispatch = useDispatch(); const navigate = useNavigate(); - const [login] = useLoginGuestMutation(); + const [login, { isLoading, error }] = useLoginGuestMutation(); + const [open, setOpen] = useState(false); const { register, @@ -28,7 +50,7 @@ function GuestLogin() { dispatch(setGuest(await login(data).unwrap())); navigate('/rsvp'); } catch (e) { - console.log(e); + setOpen(true); } }; @@ -83,6 +105,15 @@ function GuestLogin() { Log in + setOpen(false)} + autoHideDuration={5000} + > +
+ +
+
); } diff --git a/client/src/components/RsvpForm.tsx b/client/src/components/RsvpForm.tsx index 33ca108..7b2892f 100644 --- a/client/src/components/RsvpForm.tsx +++ b/client/src/components/RsvpForm.tsx @@ -17,18 +17,21 @@ import { import MailIcon from '@mui/icons-material/Mail'; import { useForm, Controller, useFieldArray } from 'react-hook-form'; import { useUpdateGuestMutation } from '../slices/api/guestSlice'; -import type { Guest } from '../models'; +import type { Guest, StatusProps } from '../models'; +import { isFetchBaseQueryError } from '../error'; +import type { Data } from '../error'; -interface StatusProps { - isError: boolean; - setOpen: (open: boolean) => void; -} - -const Status = ({ isError, setOpen }: StatusProps) => { +const Status = ({ isError, error, setOpen }: StatusProps) => { return isError ? ( - setOpen(false)}> - RSVP failed - + isFetchBaseQueryError(error) ? ( + setOpen(false)}> + {(error.data as Data).message} + + ) : ( + setOpen(false)}> + RSVP failed + + ) ) : ( setOpen(false)}> RSVP updated @@ -37,7 +40,7 @@ const Status = ({ isError, setOpen }: StatusProps) => { }; function RsvpForm() { - const [updateGuest, { isLoading, isSuccess, isError }] = + const [updateGuest, { isLoading, isSuccess, isError, error }] = useUpdateGuestMutation(); const guest: Guest = useOutletContext(); const previousPartySize = useRef((guest.partySize ?? 1) - 1); @@ -278,7 +281,7 @@ function RsvpForm() { autoHideDuration={5000} >
- +
diff --git a/client/src/error.ts b/client/src/error.ts new file mode 100644 index 0000000..8935e23 --- /dev/null +++ b/client/src/error.ts @@ -0,0 +1,11 @@ +import type { FetchBaseQueryError } from '@reduxjs/toolkit/query/react'; + +export const isFetchBaseQueryError = ( + error: any +): error is FetchBaseQueryError => { + return 'data' in error && 'message' in error.data; +}; + +export interface Data { + message: string; +} diff --git a/client/src/models.ts b/client/src/models.ts index 6840a46..5e53484 100644 --- a/client/src/models.ts +++ b/client/src/models.ts @@ -1,3 +1,6 @@ +import { SerializedError } from '@reduxjs/toolkit'; +import { FetchBaseQueryError } from '@reduxjs/toolkit/query'; + export interface Guest { id?: number; firstName: string; @@ -28,3 +31,9 @@ export interface AdminLogin { guests: Guest[]; token: string; } + +export interface StatusProps { + isError?: boolean; + error: FetchBaseQueryError | SerializedError | undefined; + setOpen: (open: boolean) => void; +} -- cgit v1.2.3