kleckrelay/src/components/MutationStatusSnackbar.tsx
2022-10-15 11:43:27 +02:00

85 lines
1.9 KiB
TypeScript

import {AxiosError} from "axios"
import {ReactElement, useEffect, useLayoutEffect, useRef, useState} from "react"
import {UseMutationResult} from "@tanstack/react-query"
import {Alert, AlertProps, Snackbar} from "@mui/material"
import {FastAPIError} from "~/utils"
import {MinimumServerResponse} from "~/server-types"
import getErrorMessage from "~/utils/get-error-message"
export interface MutationStatusSnackbarProps<
TData = unknown,
TError = unknown,
TVariables = unknown,
TContext = unknown,
> {
mutation: UseMutationResult<TData, TError, TVariables, TContext>
successMessage?: string
errorMessage?: string
}
export default function MutationStatusSnackbar<
TData extends MinimumServerResponse = MinimumServerResponse,
TError extends AxiosError = AxiosError<FastAPIError>,
TVariables = unknown,
TContext = unknown,
>({
mutation,
successMessage,
errorMessage,
}: MutationStatusSnackbarProps<
TData,
TError,
TVariables,
TContext
>): ReactElement {
const $severity = useRef<AlertProps["severity"]>()
const $message = useRef<string>()
const [open, setOpen] = useState<boolean>(false)
useLayoutEffect(() => {
setOpen(false)
}, [mutation.isSuccess, mutation.isError])
useEffect(() => {
if (mutation.isSuccess || mutation.isError) {
setOpen(true)
$severity.current = (() => {
if (mutation.isError) {
return "error"
}
if (mutation.isSuccess) {
return "success"
}
})()
$message.current = (() => {
if (mutation.isError) {
// @ts-ignore
return errorMessage ?? getErrorMessage(mutation.error)
}
if (mutation.isSuccess) {
return successMessage ?? mutation.data?.detail ?? "Success!"
}
})()
}
}, [mutation.isSuccess, mutation.isError])
return (
<Snackbar
open={open}
onClose={() => setOpen(false)}
autoHideDuration={5000}
>
<Alert severity={$severity.current} variant="filled">
{$message.current}
</Alert>
</Snackbar>
)
}