Merge pull request #2253 from bluewave-labs/feat/settings-update
feat: settings update
This commit is contained in:
11 files changed
+110
-13
No files matched your search
@@ -0,0 +1,33 @@
|
||||
import { useState } from "react";
|
||||
import { networkService } from "../main";
|
||||
import { useSelector } from "react-redux";
|
||||
import { createToast } from "../Utils/toastUtils";
|
||||
|
||||
const useSendTestEmail = () => {
|
||||
const [isSending, setIsSending] = useState(false);
|
||||
const [error, setError] = useState(null);
|
||||
const user = useSelector((state) => state.auth.user);
|
||||
|
||||
const sendTestEmail = async () => {
|
||||
try {
|
||||
setIsSending(true);
|
||||
setError(null);
|
||||
|
||||
const response = await networkService.sendTestEmail({ to: user.email });
|
||||
if (typeof response?.data?.data?.messageId !== "undefined") {
|
||||
createToast({
|
||||
body: "Test email sent successfully",
|
||||
});
|
||||
} else {
|
||||
throw new Error("Failed to send test email");
|
||||
}
|
||||
} catch (error) {
|
||||
setError(error);
|
||||
} finally {
|
||||
setIsSending(false);
|
||||
}
|
||||
};
|
||||
return [isSending, error, sendTestEmail];
|
||||
};
|
||||
|
||||
export { useSendTestEmail };
|
||||
@@ -9,11 +9,16 @@ import { useTranslation } from "react-i18next";
|
||||
import Dialog from "../../Components/Dialog";
|
||||
import { useState } from "react";
|
||||
|
||||
const SettingsDemoMonitors = ({ HEADER_SX, handleChange, isLoading }) => {
|
||||
const SettingsDemoMonitors = ({ isAdmin, HEADER_SX, handleChange, isLoading }) => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
// Local state
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
if (!isAdmin) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ConfigBox>
|
||||
@@ -83,6 +88,7 @@ const SettingsDemoMonitors = ({ HEADER_SX, handleChange, isLoading }) => {
|
||||
};
|
||||
|
||||
SettingsDemoMonitors.propTypes = {
|
||||
isAdmin: PropTypes.bool,
|
||||
handleChange: PropTypes.func,
|
||||
HEADER_SX: PropTypes.object,
|
||||
};
|
||||
|
||||
@@ -10,19 +10,28 @@ import { PropTypes } from "prop-types";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { PasswordEndAdornment } from "../../Components/Inputs/TextInput/Adornments";
|
||||
import { useSendTestEmail } from "../../Hooks/useSendTestEmail";
|
||||
|
||||
const SettingsEmail = ({
|
||||
isAdmin,
|
||||
HEADER_SX,
|
||||
handleChange,
|
||||
settingsData,
|
||||
setSettingsData,
|
||||
isPasswordSet,
|
||||
}) => {
|
||||
// Setup
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
|
||||
// Local state
|
||||
const [password, setPassword] = useState("");
|
||||
const [hasBeenReset, setHasBeenReset] = useState(false);
|
||||
|
||||
// Network
|
||||
const [isSending, error, sendTestEmail] = useSendTestEmail();
|
||||
|
||||
// Handlers
|
||||
const handlePasswordChange = (e) => {
|
||||
setPassword(e.target.value);
|
||||
setSettingsData({
|
||||
@@ -31,6 +40,10 @@ const SettingsEmail = ({
|
||||
});
|
||||
};
|
||||
|
||||
if (!isAdmin) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ConfigBox>
|
||||
<Box>
|
||||
@@ -109,6 +122,16 @@ const SettingsEmail = ({
|
||||
</Button>
|
||||
</Box>
|
||||
)}
|
||||
<Box>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="accent"
|
||||
loading={isSending}
|
||||
onClick={sendTestEmail}
|
||||
>
|
||||
Send test e-mail
|
||||
</Button>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Box>
|
||||
</ConfigBox>
|
||||
@@ -116,6 +139,7 @@ const SettingsEmail = ({
|
||||
};
|
||||
|
||||
SettingsEmail.propTypes = {
|
||||
isAdmin: PropTypes.bool,
|
||||
settingsData: PropTypes.object,
|
||||
setSettingsData: PropTypes.func,
|
||||
handleChange: PropTypes.func,
|
||||
|
||||
@@ -12,6 +12,7 @@ import { useState, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const SettingsPagespeed = ({
|
||||
isAdmin,
|
||||
HEADING_SX,
|
||||
settingsData,
|
||||
setSettingsData,
|
||||
@@ -33,6 +34,10 @@ const SettingsPagespeed = ({
|
||||
});
|
||||
};
|
||||
|
||||
if (!isAdmin) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ConfigBox>
|
||||
<Box>
|
||||
@@ -78,6 +83,7 @@ const SettingsPagespeed = ({
|
||||
};
|
||||
|
||||
SettingsPagespeed.propTypes = {
|
||||
isAdmin: PropTypes.bool,
|
||||
HEADING_SX: PropTypes.object,
|
||||
settingsData: PropTypes.object,
|
||||
setSettingsData: PropTypes.func,
|
||||
|
||||
@@ -12,10 +12,15 @@ import { PropTypes } from "prop-types";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useState } from "react";
|
||||
|
||||
const SettingsStats = ({ HEADING_SX, handleChange, settingsData, errors }) => {
|
||||
const SettingsStats = ({ isAdmin, HEADING_SX, handleChange, settingsData, errors }) => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
if (!isAdmin) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ConfigBox>
|
||||
<Box>
|
||||
@@ -75,6 +80,7 @@ const SettingsStats = ({ HEADING_SX, handleChange, settingsData, errors }) => {
|
||||
};
|
||||
|
||||
SettingsStats.propTypes = {
|
||||
isAdmin: PropTypes.bool,
|
||||
HEADING_SX: PropTypes.object,
|
||||
handleChange: PropTypes.func,
|
||||
settingsData: PropTypes.object,
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
} from "../../Features/UptimeMonitors/uptimeMonitorsSlice";
|
||||
import { useFetchSettings, useSaveSettings } from "../../Hooks/useFetchSettings";
|
||||
import { UseDeleteMonitorStats } from "../../Hooks/useDeleteMonitorStats";
|
||||
import { useIsAdmin } from "../../Hooks/useIsAdmin";
|
||||
|
||||
// Constants
|
||||
const BREADCRUMBS = [{ name: `Settings`, path: "/settings" }];
|
||||
@@ -36,6 +37,7 @@ const Settings = () => {
|
||||
// Local state
|
||||
const [settingsData, setSettingsData] = useState({});
|
||||
const [errors, setErrors] = useState({});
|
||||
|
||||
// Network
|
||||
const [isSettingsLoading, settingsError] = useFetchSettings({
|
||||
setSettingsData,
|
||||
@@ -45,6 +47,7 @@ const Settings = () => {
|
||||
const [deleteMonitorStats, isDeletingMonitorStats] = UseDeleteMonitorStats();
|
||||
|
||||
// Setup
|
||||
const isAdmin = useIsAdmin();
|
||||
const theme = useTheme();
|
||||
const HEADING_SX = { mt: theme.spacing(2), mb: theme.spacing(2) };
|
||||
const { t, i18n } = useTranslation();
|
||||
@@ -155,23 +158,27 @@ const Settings = () => {
|
||||
language={language}
|
||||
/>
|
||||
<SettingsPagespeed
|
||||
isAdmin={isAdmin}
|
||||
HEADING_SX={HEADING_SX}
|
||||
settingsData={settingsData}
|
||||
setSettingsData={setSettingsData}
|
||||
isApiKeySet={settingsData?.pagespeedKeySet ?? false}
|
||||
/>
|
||||
<SettingsStats
|
||||
isAdmin={isAdmin}
|
||||
HEADING_SX={HEADING_SX}
|
||||
settingsData={settingsData}
|
||||
handleChange={handleChange}
|
||||
errors={errors}
|
||||
/>
|
||||
<SettingsDemoMonitors
|
||||
isAdmin={isAdmin}
|
||||
HEADER_SX={HEADING_SX}
|
||||
handleChange={handleChange}
|
||||
isLoading={isSettingsLoading || isSaving || isDeletingMonitorStats}
|
||||
/>
|
||||
<SettingsEmail
|
||||
isAdmin={isAdmin}
|
||||
HEADER_SX={HEADING_SX}
|
||||
handleChange={handleChange}
|
||||
settingsData={settingsData}
|
||||
|
||||
@@ -1152,6 +1152,14 @@ class NetworkService {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// ************************************
|
||||
// Send tes t email
|
||||
// ************************************
|
||||
async sendTestEmail(config) {
|
||||
const { to } = config;
|
||||
return this.axiosInstance.post(`/monitors/test-email`, { to });
|
||||
}
|
||||
}
|
||||
|
||||
export default NetworkService;
|
||||
|
||||
@@ -582,16 +582,18 @@ class MonitorController {
|
||||
}
|
||||
|
||||
try {
|
||||
const monitor = await Monitor.findOneAndUpdate({ _id: req.params.monitorId }, [
|
||||
{
|
||||
$set: {
|
||||
isActive: { $not: "$isActive" },
|
||||
status: "$$REMOVE",
|
||||
const monitor = await Monitor.findOneAndUpdate(
|
||||
{ _id: req.params.monitorId },
|
||||
[
|
||||
{
|
||||
$set: {
|
||||
isActive: { $not: "$isActive" },
|
||||
status: "$$REMOVE",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
{ new: true }
|
||||
);
|
||||
],
|
||||
{ new: true }
|
||||
);
|
||||
monitor.isActive === true
|
||||
? await this.jobQueue.deleteJob(monitor)
|
||||
: await this.jobQueue.addJob(monitor._id, monitor);
|
||||
|
||||
@@ -158,8 +158,8 @@
|
||||
"platformRequired": "Platform is required",
|
||||
"testNotificationFailed": "Failed to send test notification",
|
||||
"monitorUpAlert": "Uptime Alert: One of your monitors is back online.\n📌 Monitor: {monitorName}\n📅 Time: {time}\n⚠️ Status: UP\n📟 Status Code: {code}\n\u200B\n",
|
||||
"monitorDownAlert": "Downtime Alert: One of your monitors went offline.\n📌 Monitor: {monitorName}\n📅 Time: {time}\n⚠️ Status: DOWN\n📟 Status Code: {code}\n\u200B\n",
|
||||
"monitorDownAlert": "Downtime Alert: One of your monitors went offline.\n📌 Monitor: {monitorName}\n📅 Time: {time}\n⚠️ Status: DOWN\n📟 Status Code: {code}\n\u200B\n",
|
||||
"sendTestEmail": "Test email sent successfully",
|
||||
"errorForValidEmailAddress": "A valid recipient email address is required.",
|
||||
"testEmailSubject": "Test Email from Monitoring System"
|
||||
"testEmailSubject": "Test E-mail from Checkmate"
|
||||
}
|
||||
@@ -130,6 +130,7 @@ class EmailService {
|
||||
try {
|
||||
const info = await this.transporter.sendMail({
|
||||
to: to,
|
||||
from: systemEmailAddress,
|
||||
subject: subject,
|
||||
html: html,
|
||||
});
|
||||
|
||||
@@ -428,6 +428,10 @@ class StringService {
|
||||
get dbUserExists() {
|
||||
return this.translationService.getTranslation("dbUserExists");
|
||||
}
|
||||
|
||||
get testEmailSubject() {
|
||||
return this.translationService.getTranslation("testEmailSubject");
|
||||
}
|
||||
}
|
||||
|
||||
export default StringService;
|
||||
Reference in new issue
Block a user