import React from "react"; import {Link} from "react-router-dom"; import Alert from "../elements/alert"; import {Collapse} from "react-collapse/lib/Collapse"; import Icon from "../elements/icon"; import { EditorState, ContentState, convertToRaw } from 'draft-js' import { Editor } from 'react-draft-wysiwyg' import draftToHtml from 'draftjs-to-html'; import htmlToDraft from 'html-to-draftjs'; import sanitizeHtml from 'sanitize-html' import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css'; import ReactTooltip from "react-tooltip"; export default class Settings extends React.Component { constructor(props) { super(props); this.state = { errors: [], settings: {}, general: { alerts: [], isOpen: true, isSaving: false, isResetting: false, keys: ["site_name", "base_url", "user_registration_enabled"] }, mail: { alerts: [], isOpen: true, isSaving: false, isResetting: false, isSending: false, test_email: "", unsavedMailSettings: false, keys: ["mail_enabled", "mail_host", "mail_port", "mail_username", "mail_password", "mail_from"] }, messages: { alerts: [], isOpen: true, isSaving: false, isResetting: false, editor: EditorState.createEmpty(), isEditing: null, keys: ["message_confirm_email", "message_accept_invite", "message_reset_password"] }, recaptcha: { alerts: [], isOpen: true, isSaving: false, isResetting: false, keys: ["recaptcha_enabled", "recaptcha_public_key", "recaptcha_private_key"] }, uncategorised: { alerts: [], isOpen: true, isSaving: false, isResetting: false, settings: [] }, }; this.parent = { api: props.api, showDialog: props.showDialog }; this.hiddenKeys = [ "recaptcha_private_key", "mail_password", "jwt_secret" ]; } isDefaultKey(key) { key = key.trim(); return this.state.general.keys.includes(key) || this.state.mail.keys.includes(key) || this.state.messages.keys.includes(key) || this.state.recaptcha.keys.includes(key) || this.hiddenKeys.includes(key); } getUncategorisedValues(res) { let uncategorised = []; for(let key in res.settings) { if (res.settings.hasOwnProperty(key) && !this.isDefaultKey(key)) { uncategorised.push({key: key, value: res.settings[key]}); } } return uncategorised; } onDeleteUncategorisedProp(index) { if (index < 0 || index >= this.state.uncategorised.settings.length) { return; } let props = this.state.uncategorised.settings.slice(); props.splice(index, 1); this.setState({ ...this.state, uncategorised: { ...this.state.uncategorised, settings: props }}); } onChangeUncategorisedValue(event, index, isKey) { if (index < 0 || index >= this.state.uncategorised.settings.length) { return; } let props = this.state.uncategorised.settings.slice(); if (isKey) { props[index].key = event.target.value; } else { props[index].value = event.target.value; } this.setState({ ...this.state, uncategorised: { ...this.state.uncategorised, settings: props }}); } onAddUncategorisedProperty() { let props = this.state.uncategorised.settings.slice(); props.push({key: "", value: ""}); this.setState({ ...this.state, uncategorised: { ...this.state.uncategorised, settings: props }}); } componentDidMount() { this.parent.api.getSettings().then((res) => { if (res.success) { let newState = { ...this.state, settings: res.settings, uncategorised: { ...this.state.uncategorised, settings: this.getUncategorisedValues(res) } }; this.setState(newState); } else { let errors = this.state.errors.slice(); errors.push({title: "Error fetching settings", message: res.msg}); this.setState({...this.state, errors: errors }); } }); } removeError(i, category = null) { if (category) { if (i >= 0 && i < this.state[category].alerts.length) { let alerts = this.state[category].alerts.slice(); alerts.splice(i, 1); this.setState({...this.state, [category]: {...this.state[category], alerts: alerts}}); } } else { if (i >= 0 && i < this.state.errors.length) { let errors = this.state.errors.slice(); errors.splice(i, 1); this.setState({...this.state, errors: errors}); } } } toggleCollapse(category) { this.setState({...this.state, [category]: {...this.state[category], isOpen: !this.state[category].isOpen}}); } createCard(category, color, icon, title, content) { let alerts = []; for (let i = 0; i < this.state[category].alerts.length; i++) { alerts.push( this.removeError(i, category)} {...this.state[category].alerts[i]}/>) } return
this.toggleCollapse(category)}>

{title}

{alerts} {content}
} createGeneralForm() { return <>
} createMailForm() { return <>

@
@
this.setState({ ...this.state, mail: {...this.state.mail, test_email: e.target.value}, })} disabled={(this.state.settings["mail_enabled"] ?? "0") !== "1"}/>
{this.state.mail.unsavedMailSettings ? You need to save your mail settings first. : null}
} getMessagesForm() { const editor = ; let messageTemplates = { "message_confirm_email": "Confirm E-Mail Message", "message_accept_invite": "Accept Invitation Message", "message_reset_password": "Reset Password Message", }; let formGroups = []; for (let key in messageTemplates) { let title = messageTemplates[key]; if (this.state.messages.isEditing === key) { formGroups.push(
{ editor }
); } else { formGroups.push(
); } } return formGroups; } getRecaptchaForm() { return <>

} getUncategorizedForm() { let tr = []; for(let i = 0; i < this.state.uncategorised.settings.length; i++) { let key = this.state.uncategorised.settings[i].key; let value = this.state.uncategorised.settings[i].value; tr.push( this.onChangeUncategorisedValue(e, i, true)} /> this.onChangeUncategorisedValue(e, i, false)} /> this.onDeleteUncategorisedProp(i)} data-type={"error"} data-tip={"Delete property"} data-place={"right"} data-effect={"solid"} data-for={"tooltip-uncategorised-" + i} /> ); } return <> {tr}
Key Value
} render() { let errors = []; for (let i = 0; i < this.state.errors.length; i++) { errors.push( this.removeError("errors", i)} {...this.state.errors[i]}/>) } const categories = { "general": {color: "primary", icon: "cogs", title: "General Settings", content: this.createGeneralForm()}, "mail": {color: "warning", icon: "envelope", title: "Mail Settings", content: this.createMailForm()}, "messages": {color: "info", icon: "copy", title: "Message Templates", content: this.getMessagesForm()}, "recaptcha": {color: "danger", icon: "google", title: "Google reCaptcha", content: this.getRecaptchaForm()}, "uncategorised": {color: "secondary", icon: "stream", title: "Uncategorised", content: this.getUncategorizedForm()}, }; let cards = []; for (let name in categories) { let category = categories[name]; cards.push(this.createCard(name, category.color, category.icon, category.title, category.content)); } return <>

Settings

  1. Home
  2. Settings
{errors}
{cards}
} onEditorStateChange(editorState) { this.setState({ ...this.state, messages: { ...this.state.messages, editor: editorState } }); }; onChangeValue(event) { const target = event.target; const name = target.name; const type = target.type; let value = target.value; if (type === "checkbox") { value = event.target.checked ? "1" : "0"; } let changedMailSettings = false; if (this.state.mail.keys.includes(name)) { changedMailSettings = true; } let newState = {...this.state, settings: {...this.state.settings, [name]: value}}; if (changedMailSettings) { newState.mail = {...this.state.mail, unsavedMailSettings: true}; } this.setState(newState); } onReset(category) { this.setState({...this.state, [category]: {...this.state[category], isResetting: true}}); this.parent.api.getSettings().then((res) => { if (!res.success) { let alerts = this.state[category].alerts.slice(); alerts.push({title: "Error fetching settings", message: res.msg}); this.setState({ ...this.state, [category]: {...this.state[category], alerts: alerts, isResetting: false} }); } else { let newState = { ...this.state }; let categoryUpdated = {...this.state[category], isResetting: false}; let newSettings = {...this.state.settings}; if (category === "uncategorised") { categoryUpdated.settings = this.getUncategorisedValues(res); for (let key in res.settings) { if (res.settings.hasOwnProperty(key) && !this.isDefaultKey(key)) { newSettings[key] = res.settings[key] ?? ""; } } } else { for (let key of this.state[category].keys) { newSettings[key] = res.settings[key] ?? ""; } if (category === "mail") { categoryUpdated.unsavedMailSettings = false; } else if (category === "messages") { categoryUpdated.isEditing = null; } } newState.settings = newSettings; newState[category] = categoryUpdated; this.setState(newState); } }); } onSave(category) { this.setState({...this.state, [category]: {...this.state[category], isSaving: true}}); if (category === "messages" && this.state.messages.isEditing) { this.closeEditor(true, () => this.onSave(category)); } let values = {}; if (category === "uncategorised") { for (let prop of this.state.uncategorised.settings) { if (prop.key) { values[prop.key] = prop.value; if (this.isDefaultKey(prop.key)) { this.parent.showDialog("You cannot use this key as property key: " + prop.key, "System specific key"); this.setState({...this.state, [category]: {...this.state[category], isSaving: false}}); return; } } } for (let key in this.state.settings) { if (this.state.settings.hasOwnProperty(key) && !this.isDefaultKey(key) && !values.hasOwnProperty(key)) { values[key] = null; } } } else { for (let key of this.state[category].keys) { if (this.hiddenKeys.includes(key) && !this.state.settings[key]) { continue; } values[key] = this.state.settings[key]; } } this.parent.api.saveSettings(values).then((res) => { let alerts = this.state[category].alerts.slice(); let categoryUpdated = {...this.state[category], isSaving: false}; if (!res.success) { alerts.push({title: "Error saving settings", message: res.msg}); } else { alerts.push({title: "Success", message: "Settings were successfully saved.", type: "success"}); if (category === "mail") categoryUpdated.unsavedMailSettings = false; this.setState({...this.state, [category]: categoryUpdated}); } categoryUpdated.alerts = alerts; this.setState({...this.state, [category]: categoryUpdated}); }); } onSendTestMail() { this.setState({...this.state, mail: {...this.state.mail, isSending: true}}); this.parent.api.sendTestMail(this.state.mail.test_email).then((res) => { let alerts = this.state.mail.alerts.slice(); let newState = {...this.state.mail, isSending: false}; if (!res.success) { alerts.push({title: "Error sending email", message: res.msg}); } else { alerts.push({ title: "Success!", message: "E-Mail was successfully sent, check your inbox.", type: "success" }); newState.test_email = ""; } newState.alerts = alerts; this.setState({...this.state, mail: newState}); }); } closeEditor(save, callback = null) { if (this.state.messages.isEditing) { const key = this.state.messages.isEditing; let newState = { ...this.state, messages: {...this.state.messages, isEditing: null }}; if (save) { newState.settings = { ...this.state.settings, [key]: draftToHtml(convertToRaw(this.state.messages.editor.getCurrentContent())), }; } callback = callback || function () { }; this.setState(newState, callback); } } openEditor(message) { this.closeEditor(true); const contentBlock = htmlToDraft(this.state.settings[message] ?? ""); if (contentBlock) { const contentState = ContentState.createFromBlockArray(contentBlock.contentBlocks); const editorState = EditorState.createWithContent(contentState); this.setState({ ...this.state, messages: { ...this.state.messages, isEditing: message, editor: editorState } }); } } }