Merge pull request #2253 from bluewave-labs/feat/settings-update

feat: settings update
This commit is contained in:
Alexander Holliday authored and GitHub committed 2025-05-12 15:46:52 -07:00
commit f43aa76804
11 files changed
+110 -13

No files matched your search

+33
View File
@@ -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,
+7 -1
View File
@@ -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,
+7
View File
@@ -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}
+8
View File
@@ -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;
+11 -9
View File
@@ -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);
+2 -2
View File
@@ -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"
}
+1
View File
@@ -130,6 +130,7 @@ class EmailService {
try {
const info = await this.transporter.sendMail({
to: to,
from: systemEmailAddress,
subject: subject,
html: html,
});
+4
View File
@@ -428,6 +428,10 @@ class StringService {
get dbUserExists() {
return this.translationService.getTranslation("dbUserExists");
}
get testEmailSubject() {
return this.translationService.getTranslation("testEmailSubject");
}
}
export default StringService;