Skip to content
Open
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
286 changes: 193 additions & 93 deletions client/src/Pages/Notifications/create/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import Typography from "@mui/material/Typography";
import Stack from "@mui/material/Stack";
import { useTheme } from "@mui/material/styles";

import { useEffect, useMemo } from "react";
import { useEffect, useMemo, useState } from "react";
import Box from "@mui/material/Box";
import { useParams } from "react-router-dom";
import { useNavigate } from "react-router-dom";
import { Controller, useForm } from "react-hook-form";
Expand Down Expand Up @@ -47,10 +48,27 @@ const NotificationsCreatePage = () => {

const watchedType = watch("type");

const [isAccessTokenSet, setIsAccessTokenSet] = useState(false);
const [accessTokenReset, setAccessTokenReset] = useState(false);
const [isAccountSidSet, setIsAccountSidSet] = useState(false);
const [accountSidReset, setAccountSidReset] = useState(false);

useEffect(() => {
if (existingNotification) {
setIsAccessTokenSet(existingNotification.accessTokenSet ?? false);
setIsAccountSidSet(existingNotification.accountSidSet ?? false);
setAccessTokenReset(false);
setAccountSidReset(false);
}
}, [existingNotification]);

useEffect(() => {
clearErrors();
}, [watchedType, clearErrors]);

const showAccessTokenInput = !isAccessTokenSet || accessTokenReset || !isEditMode;
const showAccountSidInput = !isAccountSidSet || accountSidReset || !isEditMode;

const addressConfig = useMemo(() => {
if (watchedType === "pager_duty") {
return {
Expand All @@ -77,9 +95,16 @@ const NotificationsCreatePage = () => {
}, [watchedType, t]);

const onSubmit = async (data: NotificationFormData) => {
const dataToSend = { ...data };
if (isEditMode && isAccessTokenSet && !accessTokenReset) {
delete (dataToSend as Record<string, unknown>).accessToken;
}
if (isEditMode && isAccountSidSet && !accountSidReset) {
delete (dataToSend as Record<string, unknown>).accountSid;
}
const result = isEditMode
? await patch(`/notifications/${notificationId}`, data)
: await post("/notifications", data);
? await patch(`/notifications/${notificationId}`, dataToSend)
: await post("/notifications", dataToSend);
if (result) {
navigate("/notifications");
}
Expand Down Expand Up @@ -180,24 +205,39 @@ const NotificationsCreatePage = () => {
subtitle={t("pages.notifications.form.telegram.description")}
rightContent={
<Stack spacing={theme.spacing(8)}>
<Controller
name="accessToken"
control={control}
defaultValue={"accessToken" in defaults ? defaults.accessToken : ""}
render={({ field, fieldState }) => (
<TextField
{...field}
type="text"
fieldLabel={t("pages.notifications.form.telegram.optionBotToken")}
placeholder={t(
"pages.notifications.form.telegram.placeholderBotToken"
)}
fullWidth
error={!!fieldState.error}
helperText={fieldState.error?.message ?? ""}
/>
)}
/>
{showAccessTokenInput ? (
<Controller
name="accessToken"
control={control}
defaultValue={"accessToken" in defaults ? defaults.accessToken : ""}
render={({ field, fieldState }) => (
<TextField
{...field}
type="text"
fieldLabel={t("pages.notifications.form.telegram.optionBotToken")}
placeholder={t(
"pages.notifications.form.telegram.placeholderBotToken"
)}
fullWidth
error={!!fieldState.error}
helperText={fieldState.error?.message ?? ""}
/>
)}
/>
) : (
<Box>
<Typography variant="body2">
{t("pages.notifications.form.sensitive.tokenSet")}
</Typography>
<Button
variant="contained"
color="error"
onClick={() => setAccessTokenReset(true)}
>
{t("common.buttons.reset")}
</Button>
</Box>
)}
<Controller
name="address"
control={control}
Expand All @@ -223,24 +263,39 @@ const NotificationsCreatePage = () => {
subtitle={t("pages.notifications.form.pushover.description")}
rightContent={
<Stack spacing={theme.spacing(8)}>
<Controller
name="accessToken"
control={control}
defaultValue={"accessToken" in defaults ? defaults.accessToken : ""}
render={({ field, fieldState }) => (
<TextField
{...field}
type="text"
fieldLabel={t("pages.notifications.form.pushover.optionAppToken")}
placeholder={t(
"pages.notifications.form.pushover.placeholderAppToken"
)}
fullWidth
error={!!fieldState.error}
helperText={fieldState.error?.message ?? ""}
/>
)}
/>
{showAccessTokenInput ? (
<Controller
name="accessToken"
control={control}
defaultValue={"accessToken" in defaults ? defaults.accessToken : ""}
render={({ field, fieldState }) => (
<TextField
{...field}
type="text"
fieldLabel={t("pages.notifications.form.pushover.optionAppToken")}
placeholder={t(
"pages.notifications.form.pushover.placeholderAppToken"
)}
fullWidth
error={!!fieldState.error}
helperText={fieldState.error?.message ?? ""}
/>
)}
/>
) : (
<Box>
<Typography variant="body2">
{t("pages.notifications.form.sensitive.tokenSet")}
</Typography>
<Button
variant="contained"
color="error"
onClick={() => setAccessTokenReset(true)}
>
{t("common.buttons.reset")}
</Button>
</Box>
)}
<Controller
name="address"
control={control}
Expand Down Expand Up @@ -269,42 +324,72 @@ const NotificationsCreatePage = () => {
subtitle={t("pages.notifications.form.twilio.description")}
rightContent={
<Stack spacing={theme.spacing(8)}>
<Controller
name="accountSid"
control={control}
defaultValue={"accountSid" in defaults ? defaults.accountSid : ""}
render={({ field, fieldState }) => (
<TextField
{...field}
type="text"
fieldLabel={t("pages.notifications.form.twilio.optionAccountSid")}
placeholder={t(
"pages.notifications.form.twilio.placeholderAccountSid"
)}
fullWidth
error={!!fieldState.error}
helperText={fieldState.error?.message ?? ""}
/>
)}
/>
<Controller
name="accessToken"
control={control}
defaultValue={"accessToken" in defaults ? defaults.accessToken : ""}
render={({ field, fieldState }) => (
<TextField
{...field}
type="text"
fieldLabel={t("pages.notifications.form.twilio.optionAuthToken")}
placeholder={t(
"pages.notifications.form.twilio.placeholderAuthToken"
)}
fullWidth
error={!!fieldState.error}
helperText={fieldState.error?.message ?? ""}
/>
)}
/>
{showAccountSidInput ? (
<Controller
name="accountSid"
control={control}
defaultValue={"accountSid" in defaults ? defaults.accountSid : ""}
render={({ field, fieldState }) => (
<TextField
{...field}
type="text"
fieldLabel={t("pages.notifications.form.twilio.optionAccountSid")}
placeholder={t(
"pages.notifications.form.twilio.placeholderAccountSid"
)}
fullWidth
error={!!fieldState.error}
helperText={fieldState.error?.message ?? ""}
/>
)}
/>
) : (
<Box>
<Typography variant="body2">
{t("pages.notifications.form.sensitive.accountSidSet")}
</Typography>
<Button
variant="contained"
color="error"
onClick={() => setAccountSidReset(true)}
>
{t("common.buttons.reset")}
</Button>
</Box>
)}
{showAccessTokenInput ? (
<Controller
name="accessToken"
control={control}
defaultValue={"accessToken" in defaults ? defaults.accessToken : ""}
render={({ field, fieldState }) => (
<TextField
{...field}
type="text"
fieldLabel={t("pages.notifications.form.twilio.optionAuthToken")}
placeholder={t(
"pages.notifications.form.twilio.placeholderAuthToken"
)}
fullWidth
error={!!fieldState.error}
helperText={fieldState.error?.message ?? ""}
/>
)}
/>
) : (
<Box>
<Typography variant="body2">
{t("pages.notifications.form.sensitive.tokenSet")}
</Typography>
<Button
variant="contained"
color="error"
onClick={() => setAccessTokenReset(true)}
>
{t("common.buttons.reset")}
</Button>
</Box>
)}
<Controller
name="twilioPhoneNumber"
control={control}
Expand Down Expand Up @@ -383,24 +468,39 @@ const NotificationsCreatePage = () => {
/>
)}
/>
<Controller
name="accessToken"
control={control}
defaultValue={"accessToken" in defaults ? defaults.accessToken : ""}
render={({ field, fieldState }) => (
<TextField
{...field}
type="text"
fieldLabel={t(
"pages.notifications.form.accessToken.optionAccessToken"
)}
placeholder={t("pages.notifications.form.accessToken.placeholder")}
fullWidth
error={!!fieldState.error}
helperText={fieldState.error?.message ?? ""}
/>
)}
/>
{showAccessTokenInput ? (
<Controller
name="accessToken"
control={control}
defaultValue={"accessToken" in defaults ? defaults.accessToken : ""}
render={({ field, fieldState }) => (
<TextField
{...field}
type="text"
fieldLabel={t(
"pages.notifications.form.accessToken.optionAccessToken"
)}
placeholder={t("pages.notifications.form.accessToken.placeholder")}
fullWidth
error={!!fieldState.error}
helperText={fieldState.error?.message ?? ""}
/>
)}
/>
) : (
<Box>
<Typography variant="body2">
{t("pages.notifications.form.sensitive.tokenSet")}
</Typography>
<Button
variant="contained"
color="error"
onClick={() => setAccessTokenReset(true)}
>
{t("common.buttons.reset")}
</Button>
</Box>
)}
</Stack>
}
/>
Expand Down
2 changes: 2 additions & 0 deletions client/src/Types/Notification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export interface Notification {
accessToken?: string;
accountSid?: string;
twilioPhoneNumber?: string;
accessTokenSet?: boolean;
accountSidSet?: boolean;
createdAt: string;
updatedAt: string;
}
20 changes: 15 additions & 5 deletions client/src/Validation/notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ const matrixSchema = baseSchema.extend({
.min(1, "Homeserver URL is required")
.url("Please enter a valid URL"),
roomId: z.string().min(1, "Room ID is required"),
accessToken: z.string().min(1, "Access token is required"),
accessToken: z
.union([z.string().min(1, "Access token is required"), z.literal("")])
.optional(),
});

const teamsSchema = baseSchema.extend({
Expand All @@ -53,19 +55,27 @@ const teamsSchema = baseSchema.extend({
const telegramSchema = baseSchema.extend({
type: z.literal("telegram"),
address: z.string().min(1, "Chat ID is required"),
accessToken: z.string().min(1, "Bot token is required"),
accessToken: z
.union([z.string().min(1, "Bot token is required"), z.literal("")])
.optional(),
});

const pushoverSchema = baseSchema.extend({
type: z.literal("pushover"),
address: z.string().min(1, "User key is required"),
accessToken: z.string().min(1, "App token is required"),
accessToken: z
.union([z.string().min(1, "App token is required"), z.literal("")])
.optional(),
});

const twilioSchema = baseSchema.extend({
type: z.literal("twilio"),
accountSid: z.string().min(1, "Account SID is required"),
accessToken: z.string().min(1, "Auth token is required"),
accountSid: z
.union([z.string().min(1, "Account SID is required"), z.literal("")])
.optional(),
accessToken: z
.union([z.string().min(1, "Auth token is required"), z.literal("")])
.optional(),
phone: z.string().min(1, "Recipient phone number is required"),
twilioPhoneNumber: z.string().min(1, "Twilio phone number is required"),
});
Expand Down
Loading
Loading