diff --git a/Client/src/Components/Checkbox/Checkbox.css b/Client/src/Components/Checkbox/Checkbox.css index 27c6310cc..e78fff6da 100644 --- a/Client/src/Components/Checkbox/Checkbox.css +++ b/Client/src/Components/Checkbox/Checkbox.css @@ -33,5 +33,4 @@ font-size: var(--env-var-font-size-medium); color: var(--env-var-color-5); font-weight: 500; - cursor: pointer; } diff --git a/Client/src/Components/Checkbox/CustomizableCheckbox.jsx b/Client/src/Components/Checkbox/CustomizableCheckbox.jsx index 807562f26..e39ea134b 100644 --- a/Client/src/Components/Checkbox/CustomizableCheckbox.jsx +++ b/Client/src/Components/Checkbox/CustomizableCheckbox.jsx @@ -10,9 +10,9 @@ const CustomizableCheckbox = (props) => { onChange={props.handleChange} className="custom-checkbox" type="checkbox" - id="checkbox" + id={props.id} /> - + ); }; diff --git a/Client/src/Components/RadioButton/index.jsx b/Client/src/Components/RadioButton/index.jsx index e9c874bee..40f3fc230 100644 --- a/Client/src/Components/RadioButton/index.jsx +++ b/Client/src/Components/RadioButton/index.jsx @@ -11,6 +11,7 @@ * /> * * @param {Object} props - The component props. + * @param {string} props.id - The id of the radio button. * @param {string} props.title - The title of the radio button. * @param {string} [props.desc] - The description of the radio button. * @param {string} [props.size="small"] - The size of the radio button. @@ -28,7 +29,7 @@ function RadioButton(props) { } + control={} onChange={props.onChange} label={
diff --git a/Client/src/Components/TabPanels/ProfileSettings/ProfilePanel.jsx b/Client/src/Components/TabPanels/ProfileSettings/ProfilePanel.jsx index 2675aedd9..14a3ba1b0 100644 --- a/Client/src/Components/TabPanels/ProfileSettings/ProfilePanel.jsx +++ b/Client/src/Components/TabPanels/ProfileSettings/ProfilePanel.jsx @@ -153,7 +153,7 @@ const ProfilePanel = () => {
- First Name + First name @@ -178,7 +178,7 @@ const ProfilePanel = () => {
- Last Name + Last name @@ -232,18 +232,17 @@ const ProfilePanel = () => {
- Your Photo + Your photo This photo will be displayed in your profile page. - {/* TODO - Update placeholder values with redux data */} { +const FlexibileTextField = ({ + id, + title, + type, + placeholder, + value, + onChange, +}) => { return (
{title}
{ - const portOptions = [ - { label: "Port 1", value: "Port1" }, - { label: "Port 2", value: "Port2" }, - // Add more Ports as needed - ]; + const { user } = useSelector((state) => state.auth); + const [errors, setErrors] = useState({}); - const frequencyOptions = [ - { label: "1 minute", value: "1" }, - { label: "5 minutes", value: "5" }, - // Add more Ports as needed - ]; + //General Settings Form + const [generalSettings, setGeneralSettings] = useState({ url: "", name: "" }); + //Checks Form + const [checks, setChecks] = useState({ + type: "", + // port: "" + }); + //Incidents Form + // const [notifications, setNotifications] = useState({ + // viaSms: false, + // viaEmail: false, + // viaOther: false, + // email: "", + // }); + //Advanced Settings Form + const [advancedSettings, setAdvancedSettings] = useState({ + frequency: "", + // retries: "", + // codes: "", + // redirects: "", + }); + //Proxy Settings Form + // const [proxy, setProxy] = useState({ + // enabled: false, + // protocol: "", + // address: "", + // proxy_port: "", + // }); - const [incidentEmail, setIncidentEmail] = useState(""); + const handleChange = (event, id, setState, checkbox) => { + const { value } = event.target; + setState((prev) => ({ + ...prev, + [id]: checkbox ? true : value, + })); - const [notifyViaSMS, setNotifyViaSMS] = useState(false); - const [notifyViaEmail, setNotifyViaEmail] = useState(false); - const [notifyViaCurrentEmail, setNotifyViaCurrentEmail] = useState(false); + const validation = createMonitorValidation.validate( + { [id]: value }, + { abortEarly: false } + ); - const [maxRetries, setMaxRetries] = useState(0); - const [acceptCode, setAcceptCode] = useState(0); - const [maxRedirects, setMaxRedirects] = useState(0); + setErrors((prev) => { + const updatedErrors = { ...prev }; - const [proxy, setProxy] = useState(false); + if (validation.error) { + updatedErrors[id] = validation.error.details[0].message; + } else { + delete updatedErrors[id]; + } + return updatedErrors; + }); + }; + // const handleCheck = (id, setState) => { + // setState((prev) => ({ + // ...prev, + // [id]: !prev[id], + // })); + // }; - const [proxyAddress, setProxyAddress] = useState(""); - const [proxyPort, setProxyPort] = useState(""); + const handleCreateNewMonitor = (event) => { + event.preventDefault(); + //obj to submit + const monitor = { + ...generalSettings, + ...advancedSettings, + userId: user._id, + ...checks, + }; - const [selectedMonitorType, setSelectedMonitorType] = useState(""); + const { error } = createMonitorValidation.validate(monitor, { + abortEarly: false, + }); - const [urlToMonitor, setUrlToMonitor] = useState(""); - const [friendlyName, setFriendlyName] = useState(""); - - const [port, setPort] = useState("Select a port to check"); - const [frequncy, setFrequency] = useState("1 minute"); - - const handlePortOptionChange = (newValue) => { - setPort(newValue); + if (error) { + const newErrors = {}; + error.details.forEach((err) => { + newErrors[err.path[0]] = err.message; + }); + setErrors(newErrors); + } else { + //TODO - submit logic + } }; - const handleFrequencyOptionChange = (newValue) => { - setPort(newValue); - }; + console.log(errors); - const handleUrlToMonitor = (event) => { - setUrlToMonitor(event.target.value); - console.log(urlToMonitor); - }; - - const handleFriendlyName = (event) => { - setFriendlyName(event.target.value); - console.log(friendlyName); - }; - - const handleIncidentEmail = (event) => { - setIncidentEmail(event.target.value); - console.log(incidentEmail); - }; - - const handleNotifyViaSMS = (event) => { - setNotifyViaSMS(event.target.checked); - }; - - const handleNotifyViaEmail = (event) => { - setNotifyViaEmail(event.target.checked); - }; - - const handleNotifyViaCurrentEmail = (event) => { - setNotifyViaCurrentEmail(event.target.checked); - }; - - const handleSetMaxRetries = (event) => { - setMaxRetries(event.target.value); - console.log(maxRetries); - }; - - const handleSetAcceptCode = (event) => { - setAcceptCode(event.target.value); - console.log(acceptCode); - }; - - const handleSetMaxRedirects = (event) => { - setMaxRedirects(event.target.value); - console.log(maxRedirects); - }; - - const handleEnableProxy = (event) => { - setProxy(event.target.value); - console.log(proxy); - }; - - const handleproxyAddress = (event) => { - setProxyAddress(event.target.value); - console.log(proxyAddress); - }; - - const handleproxyPort = (event) => { - setProxyPort(event.target.value); - console.log(proxyPort); - }; - - const handleMonitorTypeChange = (value) => { - setSelectedMonitorType(value); - console.log(value); - }; - - const handleCreateNewMonitor = () => { - console.log("Created"); - }; + //select values + // const ports = ["Port 1", "Port 2", "Port 3"]; + const frequencies = [1, 2, 3, 4, 5]; return ( -
+
Create new monitor
{ rightLayout={
+ handleChange(event, "url", setGeneralSettings) + } /> + {errors["url"] ? ( + + {errors["url"]} + + ) : ( + "" + )}
+ handleChange(event, "name", setGeneralSettings) + } /> + {errors["name"] ? ( + + {errors["name"]} + + ) : ( + "" + )}
} /> @@ -163,42 +171,62 @@ const CreateNewMonitor = () => { rightLayout={
handleMonitorTypeChange("http")} + checked={checks.type === "http"} + onChange={(event) => handleChange(event, "type", setChecks)} />
handleMonitorTypeChange("ping")} + checked={checks.type === "ping"} + onChange={(event) => handleChange(event, "type", setChecks)} />
- handleMonitorTypeChange("port")} + checked={checks.type === "port"} + onChange={(event) => handleChange(event, "type", setChecks)} />
- -
+ +
*/} + {errors["type"] ? ( + + {errors["type"]} + + ) : ( + "" + )}
} /> -
+ {/* TODO */} + {/*
{
handleCheck("viaSms", setNotifications)} />
handleCheck("viaEmail", setNotifications)} />
handleCheck("viaOther", setNotifications)} />
+ handleChange(event, "email", setNotifications) + } />
} - /> + /> */}
{
Check frequency
- + handleChange(event, "frequency", setAdvancedSettings) + } + > + {frequencies.map((freq) => ( + + {freq} {freq === 1 ? "minute" : "minutes"} + + ))} + +
+ {/* TODO */} + {/* + handleChange(event, "retries", setAdvancedSettings) + } />
-
- Maximum retries before the service is marked as down -
+ handleChange(event, "codes", setAdvancedSettings) + } />
-
Accepted status codes
-
-
Maximum redirects
- + value={advancedSettings.redirects} + onChange={(event) => + handleChange(event, "redirects", setAdvancedSettings) + } + /> */}
} /> -
+ {/* TODO */} + {/*
{ rightLayout={
handleCheck("enabled", setProxy)} />
-
Proxy protocol
- + handleChange(event, "protocol", setProxy)} + />
-
Proxy address
- + handleChange(event, "address", setProxy)} + />
-
Proxy port
- + handleChange(event, "proxy_port", setProxy)} + />
} - /> + /> */}
@@ -326,10 +389,10 @@ const CreateNewMonitor = () => { level="primary" label="Create new monitor" sx={{ width: "210px", fontSize: "var(--env-var-font-size-medium)" }} - onClick={() => handleCreateNewMonitor()} + onClick={handleCreateNewMonitor} />
-
+ ); }; diff --git a/Client/src/Pages/Monitors/index.jsx b/Client/src/Pages/Monitors/index.jsx index 00df4ee24..5f7b4b9af 100644 --- a/Client/src/Pages/Monitors/index.jsx +++ b/Client/src/Pages/Monitors/index.jsx @@ -16,8 +16,7 @@ const Monitors = () => { return (
- {/* */} - +
); }; diff --git a/Client/src/Pages/Settings/index.css b/Client/src/Pages/Settings/index.css index 0769c9117..b0c2afb8d 100644 --- a/Client/src/Pages/Settings/index.css +++ b/Client/src/Pages/Settings/index.css @@ -173,7 +173,6 @@ .settings .MuiStack-root:has(p.MuiTypography-root.input-error) { position: relative; - margin-bottom: 8px; } .settings .text-field-icon { position: absolute; diff --git a/Client/src/Validation/validation.js b/Client/src/Validation/validation.js index c2249fc93..802965870 100644 --- a/Client/src/Validation/validation.js +++ b/Client/src/Validation/validation.js @@ -82,43 +82,41 @@ const editProfileValidation = joi.object({ }), }); +const passwordSchema = joi + .string() + .trim() + .min(8) + .messages({ + "string.empty": "*Password is required.", + "string.min": "*Password must be at least 8 characters long.", + }) + .custom((value, helpers) => { + if (!/[A-Z]/.test(value)) { + return helpers.message( + "*Password must contain at least one uppercase letter." + ); + } + if (!/[a-z]/.test(value)) { + return helpers.message( + "*Password must contain at least one lowercase letter." + ); + } + if (!/\d/.test(value)) { + return helpers.message("*Password must contain at least one number."); + } + if (!/[!@#$%^&*]/.test(value)) { + return helpers.message( + "*Password must contain at least one special character." + ); + } + + return value; + }); + const editPasswordValidation = joi.object({ // TBD - validation for current password ? - password : joi - .string().trim() - .messages({ - "string.empty": "*Current password is required.", - }), - newpassword: joi - .string() - .trim() - .min(8) - .messages({ - "string.empty": "*Password is required.", - "string.min": "*Password must be at least 8 characters long.", - }) - .custom((value, helpers) => { - if (!/[A-Z]/.test(value)) { - return helpers.message( - "*Password must contain at least one uppercase letter." - ); - } - if (!/[a-z]/.test(value)) { - return helpers.message( - "*Password must contain at least one lowercase letter." - ); - } - if (!/\d/.test(value)) { - return helpers.message("*Password must contain at least one number."); - } - if (!/[!@#$%^&*]/.test(value)) { - return helpers.message( - "*Password must contain at least one special character." - ); - } - - return value; - }), + password: passwordSchema, + newpassword: passwordSchema, confirm: joi .string() .trim() @@ -126,15 +124,22 @@ const editPasswordValidation = joi.object({ "string.empty": "*Password confirmation is required.", }) .custom((value, helpers) => { - const { password } = helpers.prefs.context; - if (value !== password) { + const { newpassword } = helpers.prefs.context; + if (value !== newpassword) { return helpers.message("*Passwords do not match."); } return value; }), }); +const createMonitorValidation = joi.object({ + url: joi.string().trim().messages({ "string.empty": "*Url is required." }), + name: joi.string().trim().messages({ "string.empty": "*Name is required." }), + type: joi.string().trim().messages({ "string.empty": "*Type is required." }), +}); + export { + createMonitorValidation, registerValidation, loginValidation, recoveryValidation,