285 lines
7.2 KiB
React
285 lines
7.2 KiB
React
// Components
|
|
import Stack from "@mui/material/Stack";
|
|
import Typography from "@mui/material/Typography";
|
|
import Breadcrumbs from "../../../Components/Breadcrumbs";
|
|
import Button from "@mui/material/Button";
|
|
import ConfigBox from "../../../Components/ConfigBox";
|
|
import Box from "@mui/material/Box";
|
|
import Select from "../../../Components/Inputs/Select";
|
|
import TextInput from "../../../Components/Inputs/TextInput";
|
|
import Dialog from "../../../Components/Dialog";
|
|
|
|
// Utils
|
|
import { useState } from "react";
|
|
import { useTheme } from "@emotion/react";
|
|
import {
|
|
useCreateNotification,
|
|
useGetNotificationById,
|
|
useEditNotification,
|
|
useTestNotification,
|
|
useDeleteNotification,
|
|
} from "../../../Hooks/useNotifications";
|
|
import { notificationValidation } from "../../../Validation/validation";
|
|
import { createToast } from "../../../Utils/toastUtils";
|
|
import { useTranslation } from "react-i18next";
|
|
import { useParams, useNavigate } from "react-router-dom";
|
|
import {
|
|
NOTIFICATION_TYPES,
|
|
TITLE_MAP,
|
|
DESCRIPTION_MAP,
|
|
LABEL_MAP,
|
|
PLACEHOLDER_MAP,
|
|
} from "../utils";
|
|
|
|
// Setup
|
|
|
|
const CreateNotifications = () => {
|
|
const { notificationId } = useParams();
|
|
const navigate = useNavigate();
|
|
const theme = useTheme();
|
|
const [createNotification, isCreating] = useCreateNotification();
|
|
const [editNotification, isEditing] = useEditNotification();
|
|
const [testNotification, isTesting] = useTestNotification();
|
|
const [deleteNotification, isDeleting] = useDeleteNotification();
|
|
|
|
const BREADCRUMBS = [
|
|
{ name: "notifications", path: "/notifications" },
|
|
{
|
|
name: notificationId ? "edit" : "create",
|
|
path: notificationId ? `/notifications/${notificationId}` : "/notifications/create",
|
|
},
|
|
];
|
|
|
|
// Redux state
|
|
|
|
// local state
|
|
const [notification, setNotification] = useState({
|
|
notificationName: "",
|
|
address: "",
|
|
type: NOTIFICATION_TYPES[0]._id,
|
|
});
|
|
const [errors, setErrors] = useState({});
|
|
const { t } = useTranslation();
|
|
|
|
const [notificationIsLoading] = useGetNotificationById(notificationId, setNotification);
|
|
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
|
|
const getNotificationTypeValue = (typeId) => {
|
|
return NOTIFICATION_TYPES.find((type) => type._id === typeId)?.value || "email";
|
|
};
|
|
|
|
const extractError = (error, field) =>
|
|
error?.details.find((d) => d.path.includes(field))?.message;
|
|
|
|
// handlers
|
|
const onSubmit = (e) => {
|
|
e.preventDefault();
|
|
const form = {
|
|
...notification,
|
|
type: getNotificationTypeValue(notification.type),
|
|
};
|
|
|
|
let error = null;
|
|
|
|
error = notificationValidation.validate(form, { abortEarly: false }).error;
|
|
|
|
if (error) {
|
|
const newErrors = {};
|
|
error.details.forEach((err) => {
|
|
newErrors[err.path[0]] = err.message;
|
|
});
|
|
createToast({ body: Object.values(newErrors)[0] });
|
|
setErrors(newErrors);
|
|
return;
|
|
}
|
|
|
|
if (notificationId) {
|
|
editNotification(notificationId, form);
|
|
} else {
|
|
createNotification(form);
|
|
}
|
|
};
|
|
|
|
const onChange = (e) => {
|
|
const { name, value } = e.target;
|
|
let rawNotification = { ...notification, [name]: value };
|
|
let newNotification = {
|
|
...rawNotification,
|
|
type: getNotificationTypeValue(rawNotification.type),
|
|
};
|
|
|
|
const { error } = notificationValidation.validate(newNotification, {
|
|
abortEarly: false,
|
|
});
|
|
let validationError = { ...errors };
|
|
|
|
if (name === "type") {
|
|
validationError["type"] = extractError(error, "type");
|
|
validationError["address"] = extractError(error, "address");
|
|
} else {
|
|
validationError[name] = extractError(error, name);
|
|
}
|
|
|
|
setNotification(rawNotification);
|
|
setErrors(validationError);
|
|
};
|
|
|
|
const onTestNotification = () => {
|
|
const form = {
|
|
...notification,
|
|
type: getNotificationTypeValue(notification.type),
|
|
};
|
|
|
|
let error = null;
|
|
|
|
error = notificationValidation.validate(form, { abortEarly: false }).error;
|
|
|
|
if (error) {
|
|
const newErrors = {};
|
|
error.details.forEach((err) => {
|
|
newErrors[err.path[0]] = err.message;
|
|
});
|
|
createToast({ body: Object.values(newErrors)[0] });
|
|
setErrors(newErrors);
|
|
return;
|
|
}
|
|
|
|
testNotification(form);
|
|
};
|
|
|
|
const onDelete = () => {
|
|
if (notificationId) {
|
|
deleteNotification(notificationId, () => navigate("/notifications"));
|
|
}
|
|
};
|
|
|
|
const type = getNotificationTypeValue(notification.type);
|
|
return (
|
|
<Stack gap={theme.spacing(10)}>
|
|
<Breadcrumbs list={BREADCRUMBS} />
|
|
<Typography variant="h1">{t("createNotifications.title")}</Typography>
|
|
<Stack
|
|
component="form"
|
|
onSubmit={onSubmit}
|
|
noValidate
|
|
gap={theme.spacing(12)}
|
|
mt={theme.spacing(6)}
|
|
>
|
|
<ConfigBox>
|
|
<Box>
|
|
<Typography
|
|
component="h2"
|
|
variant="h2"
|
|
>
|
|
{t("createNotifications.nameSettings.title")}
|
|
</Typography>
|
|
<Typography component="p">
|
|
{t("createNotifications.nameSettings.description")}
|
|
</Typography>
|
|
</Box>
|
|
<Stack gap={theme.spacing(12)}>
|
|
<TextInput
|
|
label={t("createNotifications.nameSettings.nameLabel")}
|
|
name="notificationName"
|
|
placeholder={t("createNotifications.nameSettings.namePlaceholder")}
|
|
value={notification.notificationName}
|
|
onChange={onChange}
|
|
error={Boolean(errors.notificationName)}
|
|
helperText={errors["notificationName"]}
|
|
/>
|
|
</Stack>
|
|
</ConfigBox>
|
|
<ConfigBox>
|
|
<Box>
|
|
<Typography
|
|
component="h2"
|
|
variant="h2"
|
|
>
|
|
{t("createNotifications.typeSettings.title")}
|
|
</Typography>
|
|
<Typography component="p">
|
|
{t("createNotifications.typeSettings.description")}
|
|
</Typography>
|
|
</Box>
|
|
<Stack gap={theme.spacing(12)}>
|
|
<Select
|
|
items={NOTIFICATION_TYPES}
|
|
label="Type"
|
|
name="type"
|
|
value={notification.type}
|
|
onChange={onChange}
|
|
/>
|
|
</Stack>
|
|
</ConfigBox>
|
|
<ConfigBox>
|
|
<Box>
|
|
<Typography
|
|
component="h2"
|
|
variant="h2"
|
|
>
|
|
{t(TITLE_MAP[type])}
|
|
</Typography>
|
|
<Typography component="p">{t(DESCRIPTION_MAP[type])}</Typography>
|
|
</Box>
|
|
<Stack gap={theme.spacing(12)}>
|
|
<TextInput
|
|
label={t(LABEL_MAP[type])}
|
|
name="address"
|
|
placeholder={t(PLACEHOLDER_MAP[type])}
|
|
value={notification.address}
|
|
onChange={onChange}
|
|
error={Boolean(errors.address)}
|
|
helperText={errors["address"]}
|
|
/>
|
|
</Stack>
|
|
</ConfigBox>
|
|
|
|
<Stack
|
|
direction="row"
|
|
justifyContent="flex-end"
|
|
spacing={theme.spacing(2)}
|
|
>
|
|
<Button
|
|
loading={isTesting}
|
|
variant="contained"
|
|
color="secondary"
|
|
onClick={onTestNotification}
|
|
>
|
|
{t("createNotifications.testNotification")}
|
|
</Button>
|
|
{notificationId && (
|
|
<Button
|
|
loading={isDeleting}
|
|
variant="contained"
|
|
color="error"
|
|
onClick={() => setIsOpen(true)}
|
|
>
|
|
{t("delete")}
|
|
</Button>
|
|
)}
|
|
<Button
|
|
loading={isCreating || isEditing || notificationIsLoading}
|
|
type="submit"
|
|
variant="contained"
|
|
color="accent"
|
|
>
|
|
{t("submit")}
|
|
</Button>
|
|
</Stack>
|
|
</Stack>
|
|
<Dialog
|
|
open={isOpen}
|
|
onClose={() => setIsOpen(false)}
|
|
onCancel={() => setIsOpen(false)}
|
|
title={t("createNotifications.dialogDeleteTitle")}
|
|
confirmationButtonLabel={t("createNotifications.dialogDeleteConfirm")}
|
|
onConfirm={onDelete}
|
|
isLoading={isDeleting}
|
|
/>
|
|
</Stack>
|
|
);
|
|
};
|
|
|
|
export default CreateNotifications;
|