diff --git a/Containers/UserSettings/AppriseAlertSettings/AppriseAlertSettings.js b/Containers/UserSettings/AppriseAlertSettings/AppriseAlertSettings.js new file mode 100644 index 0000000..e62a41f --- /dev/null +++ b/Containers/UserSettings/AppriseAlertSettings/AppriseAlertSettings.js @@ -0,0 +1,210 @@ +//Lib +import { useEffect } from 'react'; +import { toast } from 'react-toastify'; +import 'react-toastify/dist/ReactToastify.css'; +import classes from '../UserSettings.module.css'; +import { useState } from 'react'; +import { SpinnerCircularFixed } from 'spinners-react'; + +//Components +import Error from '../../../Components/UI/Error/Error'; +import Switch from '../../../Components/UI/Switch/Switch'; +import AppriseURLs from './AppriseURLs/AppriseURLs'; +import AppriseMode from './AppriseMode/AppriseMode'; + +export default function AppriseAlertSettings() { + //Var + const toastOptions = { + position: 'top-right', + autoClose: 5000, + hideProgressBar: false, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + progress: undefined, + //Callback > re-enabled button after notification. + onClose: () => setDisabled(false), + }; + + ////State + const [checkIsLoading, setCheckIsLoading] = useState(true); + const [error, setError] = useState(); + const [disabled, setDisabled] = useState(false); + const [checked, setChecked] = useState(); + const [testIsLoading, setTestIsLoading] = useState(false); + const [info, setInfo] = useState(false); + + ////LifeCycle + //Component did mount + useEffect(() => { + //Initial fetch to get the status of Apprise Alert + const getAppriseAlert = async () => { + try { + const response = await fetch('/api/account/getAppriseAlert', { + method: 'GET', + headers: { + 'Content-type': 'application/json', + }, + }); + setChecked((await response.json()).appriseAlert); + setCheckIsLoading(false); + } catch (error) { + setError( + 'Fetching apprise alert setting failed. Contact your administrator.' + ); + console.log('Fetching apprise alert setting failed.'); + setCheckIsLoading(false); + } + }; + getAppriseAlert(); + }, []); + + ////Functions + //Switch to enable/disable Apprise notifications + const onChangeSwitchHandler = async (data) => { + //Remove old error + setError(); + //Disabled button + setDisabled(true); + await fetch('/api/account/updateAppriseAlert', { + method: 'PUT', + headers: { + 'Content-type': 'application/json', + }, + body: JSON.stringify(data), + }) + .then((response) => { + console.log(response); + if (response.ok) { + if (data.appriseAlert) { + setChecked(!checked); + toast.success( + 'Apprise notifications enabled.', + toastOptions + ); + } else { + setChecked(!checked); + toast.success( + 'Apprise notifications disabled.', + toastOptions + ); + } + } else { + setError('Update apprise alert setting failed.'); + setTimeout(() => { + setError(); + setDisabled(false); + }, 4000); + } + }) + .catch((error) => { + console.log(error); + setError('Update Apprise failed. Contact your administrator.'); + setTimeout(() => { + setError(); + setDisabled(false); + }, 4000); + }); + }; + + //Send Apprise test notification to services + const onSendTestAppriseHandler = async () => { + //Loading + setTestIsLoading(true); + //Remove old error + setError(); + try { + const response = await fetch('/api/account/sendTestApprise', { + method: 'POST', + headers: { + 'Content-type': 'application/json', + }, + body: JSON.stringify({ sendTestApprise: true }), + }); + const result = await response.json(); + if (!response.ok) { + setTestIsLoading(false); + setError(result.message); + } else { + setTestIsLoading(false); + setInfo(true); + setTimeout(() => { + setInfo(false); + }, 4000); + } + } catch (error) { + setTestIsLoading(false); + console.log(error); + setError('Send notification failed. Contact your administrator.'); + setTimeout(() => { + setError(); + }, 4000); + } + }; + + return ( + <> + {/* APPRISE ALERT */} +
+
+

Apprise alert

+
+
+
+ {/* NOTIFY SWITCH */} + {checkIsLoading ? ( + + ) : ( + + onChangeSwitchHandler({ appriseAlert: e }) + } + /> + )} + {/* APPRISE SERVICES URLS */} + + {/* APPRISE MODE SELECTION */} + + {/* APPRISE TEST BUTTON */} + {testIsLoading ? ( + + ) : ( + + )} + {info && ( + + Notification successfully sent. + + )} + {error && } +
+
+
+ + ); +} diff --git a/Containers/UserSettings/AppriseAlertSettings/AppriseMode/AppriseMode.js b/Containers/UserSettings/AppriseAlertSettings/AppriseMode/AppriseMode.js new file mode 100644 index 0000000..029cbf8 --- /dev/null +++ b/Containers/UserSettings/AppriseAlertSettings/AppriseMode/AppriseMode.js @@ -0,0 +1,173 @@ +//Lib +import { useEffect } from 'react'; +import classes from '../../UserSettings.module.css'; +import { useState } from 'react'; +import { SpinnerCircularFixed } from 'spinners-react'; +import { useForm } from 'react-hook-form'; + +//Components +import Error from '../../../../Components/UI/Error/Error'; + +export default function AppriseMode() { + //Var + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ mode: 'onBlur' }); + + ////State + const [formIsLoading, setFormIsLoading] = useState(false); + const [modeFormIsSaved, setModeFormIsSaved] = useState(false); + const [error, setError] = useState(false); + const [displayStatelessURL, setDisplayStatelessURL] = useState(false); + const [appriseMode, setAppriseMode] = useState(''); + const [appriseStatelessURL, setAppriseStatelessURL] = useState(); + + ////LifeCycle + //Component did mount + useEffect(() => { + //Initial fetch to get Apprise Mode enabled + const getAppriseMode = async () => { + try { + const response = await fetch('/api/account/getAppriseMode', { + method: 'GET', + headers: { + 'Content-type': 'application/json', + }, + }); + const { appriseStatelessURL, appriseMode } = + await response.json(); + setAppriseMode(appriseMode); + if (appriseMode == 'stateless') { + setAppriseStatelessURL(appriseStatelessURL); + setDisplayStatelessURL(true); + } + } catch (error) { + console.log('Fetching Apprise Mode failed.'); + } + }; + getAppriseMode(); + }, []); + + ////Functions + //Form submit handler to modify Apprise Mode + const modeFormSubmitHandler = async (data) => { + //Remove old error + setError(); + //Loading button on submit to avoid multiple send. + setFormIsLoading(true); + //POST API to update Apprise Mode + try { + const response = await fetch('/api/account/updateAppriseMode', { + method: 'PUT', + headers: { + 'Content-type': 'application/json', + }, + body: JSON.stringify(data), + }); + const result = await response.json(); + + if (!response.ok) { + setFormIsLoading(false); + setError(result.message); + setTimeout(() => setError(), 4000); + } else { + setFormIsLoading(false); + setModeFormIsSaved(true); + setTimeout(() => setModeFormIsSaved(false), 3000); + } + } catch (error) { + setFormIsLoading(false); + setError('Change mode failed. Contact your administrator.'); + setTimeout(() => { + setError(); + }, 4000); + } + }; + + return ( + <> + {/* APPRISE MODE SELECTION */} +
+
Apprise mode
+
+ {formIsLoading && ( + + )} + {modeFormIsSaved && ( +
+ ✅ Apprise mode has been saved. +
+ )} +
+
+ {error && } +
+
+ + +
+ {displayStatelessURL && ( + + )} + {errors.appriseStatelessURL && ( + + {errors.appriseStatelessURL.message} + + )} +
+ + ); +} diff --git a/Containers/UserSettings/AppriseAlertSettings/AppriseURLs/AppriseURLs.js b/Containers/UserSettings/AppriseAlertSettings/AppriseURLs/AppriseURLs.js new file mode 100644 index 0000000..2962ac7 --- /dev/null +++ b/Containers/UserSettings/AppriseAlertSettings/AppriseURLs/AppriseURLs.js @@ -0,0 +1,162 @@ +//Lib +import { useEffect } from 'react'; +import classes from '../../UserSettings.module.css'; +import { useState } from 'react'; +import { SpinnerCircularFixed } from 'spinners-react'; +import { useForm } from 'react-hook-form'; + +//Components +import Error from '../../../../Components/UI/Error/Error'; + +export default function AppriseURLs() { + //Var + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ mode: 'onBlur' }); + + ////State + const [formIsLoading, setFormIsLoading] = useState(false); + const [urlsFormIsSaved, setUrlsFormIsSaved] = useState(false); + const [appriseServicesList, setAppriseServicesList] = useState(); + const [error, setError] = useState(); + + ////LifeCycle + //Component did mount + useEffect(() => { + //Initial fetch to build the list of Apprise Services enabled + const getAppriseServices = async () => { + try { + const response = await fetch( + '/api/account/getAppriseServices', + { + method: 'GET', + headers: { + 'Content-type': 'application/json', + }, + } + ); + let servicesArray = (await response.json()).appriseServices; + const AppriseServicesListToText = () => { + let list = ''; + for (let service of servicesArray) { + list += service + '\n'; + } + return list; + }; + setAppriseServicesList(AppriseServicesListToText()); + } catch (error) { + console.log('Fetching Apprise services list failed.'); + } + }; + getAppriseServices(); + }, []); + + ////Functions + //Form submit handler to modify Apprise services + const urlsFormSubmitHandler = async (data) => { + //Remove old error + setError(); + //Loading button on submit to avoid multiple send. + setFormIsLoading(true); + //POST API to update Apprise Services + try { + const response = await fetch('/api/account/updateAppriseServices', { + method: 'PUT', + headers: { + 'Content-type': 'application/json', + }, + body: JSON.stringify(data), + }); + const result = await response.json(); + + if (!response.ok) { + setFormIsLoading(false); + setError(result.message); + setTimeout(() => setError(), 4000); + } else { + setFormIsLoading(false); + setUrlsFormIsSaved(true); + setTimeout(() => setUrlsFormIsSaved(false), 3000); + } + } catch (error) { + setFormIsLoading(false); + setError( + 'Failed to update your services. Contact your administrator.' + ); + setTimeout(() => { + setError(); + }, 4000); + } + }; + + return ( + <> + {/* APPRISE SERVICES URLS */} +
+
Apprise URLs
+ {error && } +
+ {formIsLoading && ( + + )} + {urlsFormIsSaved && ( +
+ ✅ Apprise configuration has been saved. +
+ )} +
+
+
+