'use strict'; import React, {Component} from 'react'; import PropTypes from 'prop-types'; import {Trans} from 'react-i18next'; import {withTranslation} from '../../lib/i18n'; import {LinkButton, requiresAuthenticatedUser, Title, withPageHelpers} from '../../lib/page'; import { ACEEditor, AlignedRow, Button, ButtonRow, Dropdown, Fieldset, filterData, Form, FormSendMethod, InputField, TableSelect, TextArea, withForm, withFormErrorHandlers } from '../../lib/form'; import {withErrorHandling} from '../../lib/error-handling'; import {NamespaceSelect, validateNamespace} from '../../lib/namespace'; import {DeleteModalDialog} from "../../lib/modals"; import mailtrainConfig from 'mailtrainConfig'; import {getTrustedUrl, getUrl} from "../../lib/urls"; import {ActionLink, Icon} from "../../lib/bootstrap-components"; import styles from "../../lib/styles.scss"; import formsStyles from "./styles.scss"; import axios from "../../lib/axios"; import {withComponentMixins} from "../../lib/decorator-helpers"; @withComponentMixins([ withTranslation, withForm, withErrorHandling, withPageHelpers, requiresAuthenticatedUser ]) export default class CUD extends Component { constructor(props) { super(props); this.state = { previewContents: null, previewFullscreen: false }; this.serverValidatedFields = [ 'layout', 'web_subscribe', 'web_confirm_subscription_notice', 'mail_confirm_subscription_html', 'mail_confirm_subscription_text', 'mail_already_subscribed_html', 'mail_already_subscribed_text', 'web_subscribed_notice', 'mail_subscription_confirmed_html', 'mail_subscription_confirmed_text', 'web_manage', 'web_manage_address', 'web_updated_notice', 'web_unsubscribe', 'web_confirm_unsubscription_notice', 'mail_confirm_unsubscription_html', 'mail_confirm_unsubscription_text', 'mail_confirm_address_change_html', 'mail_confirm_address_change_text', 'web_unsubscribed_notice', 'mail_unsubscription_confirmed_html', 'mail_unsubscription_confirmed_text', 'web_manual_unsubscribe_notice', 'web_privacy_policy_notice' ]; this.initForm({ serverValidation: { url: 'rest/forms-validate', changed: this.serverValidatedFields }, onChange: { previewList: (newState, key, oldValue, newValue) => { newState.formState.setIn(['data', 'previewContents', 'value'], null); } } }); const t = props.t; const helpEmailText = t('thePlaintextVersionForThisEmail'); const helpMjmlGeneral = Custom forms use MJML for formatting. See the MJML documentation here; this.templateSettings = { layout: { label: t('layout'), mode: 'html', help: helpMjmlGeneral, isLayout: true }, form_input_style: { label: t('formInputStyle'), mode: 'css', help: t('thisCssStylesheetDefinesTheAppearanceOf') }, web_subscribe: { label: t('webSubscribe'), mode: 'html', help: helpMjmlGeneral }, web_confirm_subscription_notice: { label: t('webConfirmSubscriptionNotice'), mode: 'html', help: helpMjmlGeneral }, mail_confirm_subscription_html: { label: t('mailConfirmSubscriptionMjml'), mode: 'html', help: helpMjmlGeneral }, mail_confirm_subscription_text: { label: t('mailConfirmSubscriptionText'), mode: 'text', help: helpEmailText }, mail_already_subscribed_html: { label: t('mailAlreadySubscribedMjml'), mode: 'html', help: helpMjmlGeneral }, mail_already_subscribed_text: { label: t('mailAlreadySubscribedText'), mode: 'text', help: helpEmailText }, web_subscribed_notice: { label: t('webSubscribedNotice'), mode: 'html', help: helpMjmlGeneral }, mail_subscription_confirmed_html: { label: t('mailSubscriptionConfirmedMjml'), mode: 'html', help: helpMjmlGeneral }, mail_subscription_confirmed_text: { label: t('mailSubscriptionConfirmedText'), mode: 'text', help: helpEmailText }, web_manage: { label: t('webManagePreferences'), mode: 'html', help: helpMjmlGeneral }, web_manage_address: { label: t('webManageAddress'), mode: 'html', help: helpMjmlGeneral }, mail_confirm_address_change_html: { label: t('mailConfirmAddressChangeMjml'), mode: 'html', help: helpMjmlGeneral }, mail_confirm_address_change_text: { label: t('mailConfirmAddressChangeText'), mode: 'text', help: helpEmailText }, web_updated_notice: { label: t('webUpdatedNotice'), mode: 'html', help: helpMjmlGeneral }, web_unsubscribe: { label: t('webUnsubscribe'), mode: 'html', help: helpMjmlGeneral }, web_confirm_unsubscription_notice: { label: t('webConfirmUnsubscriptionNotice'), mode: 'html', help: helpMjmlGeneral }, mail_confirm_unsubscription_html: { label: t('mailConfirmUnsubscriptionMjml'), mode: 'html', help: helpMjmlGeneral }, mail_confirm_unsubscription_text: { label: t('mailConfirmUnsubscriptionText'), mode: 'text', help: helpEmailText }, web_unsubscribed_notice: { label: t('webUnsubscribedNotice'), mode: 'html', help: helpMjmlGeneral }, mail_unsubscription_confirmed_html: { label: t('mailUnsubscriptionConfirmedMjml'), mode: 'html', help: helpMjmlGeneral }, mail_unsubscription_confirmed_text: { label: t('mailUnsubscriptionConfirmedText'), mode: 'text', help: helpEmailText }, web_manual_unsubscribe_notice: { label: t('webManualUnsubscribeNotice'), mode: 'html', help: helpMjmlGeneral }, web_privacy_policy_notice: { label: t('privacyPolicy'), mode: 'html', help: helpMjmlGeneral } }; this.templateGroups = { general: { label: t('general'), options: [ 'layout', 'form_input_style' ] }, subscribe: { label: t('subscribe'), options: [ 'web_subscribe', 'web_confirm_subscription_notice', 'mail_confirm_subscription_html', 'mail_confirm_subscription_text', 'mail_already_subscribed_html', 'mail_already_subscribed_text', 'web_subscribed_notice', 'mail_subscription_confirmed_html', 'mail_subscription_confirmed_text' ] }, manage: { label: t('manage'), options: [ 'web_manage', 'web_manage_address', 'mail_confirm_address_change_html', 'mail_confirm_address_change_text', 'web_updated_notice' ] }, unsubscribe: { label: t('unsubscribe'), options: [ 'web_unsubscribe', 'web_confirm_unsubscription_notice', 'mail_confirm_unsubscription_html', 'mail_confirm_unsubscription_text', 'web_unsubscribed_notice', 'mail_unsubscription_confirmed_html', 'mail_unsubscription_confirmed_text', 'web_manual_unsubscribe_notice' ] }, gdpr: { label: t('dataProtection'), options: [ 'web_privacy_policy_notice' ] }, }; } static propTypes = { action: PropTypes.string.isRequired, entity: PropTypes.object } supplyDefaults(data) { for (const key in mailtrainConfig.defaultCustomFormValues) { if (!data[key]) { data[key] = mailtrainConfig.defaultCustomFormValues[key]; } } } getFormValuesMutator(data, originalData) { this.supplyDefaults(data); data.selectedTemplate = (originalData && originalData.selectedTemplate) || 'layout'; } submitFormValuesMutator(data) { return filterData(data, ['name', 'description', 'layout', 'form_input_style', 'namespace', 'web_subscribe', 'web_confirm_subscription_notice', 'mail_confirm_subscription_html', 'mail_confirm_subscription_text', 'mail_already_subscribed_html', 'mail_already_subscribed_text', 'web_subscribed_notice', 'mail_subscription_confirmed_html', 'mail_subscription_confirmed_text', 'web_manage', 'web_manage_address', 'web_updated_notice', 'web_unsubscribe', 'web_confirm_unsubscription_notice', 'mail_confirm_unsubscription_html', 'mail_confirm_unsubscription_text', 'mail_confirm_address_change_html', 'mail_confirm_address_change_text', 'web_unsubscribed_notice', 'mail_unsubscription_confirmed_html', 'mail_unsubscription_confirmed_text', 'web_manual_unsubscribe_notice', 'web_privacy_policy_notice' ]); } componentDidMount() { if (this.props.entity) { this.getFormValuesFromEntity(this.props.entity); } else { const data = { name: '', description: '', selectedTemplate: 'layout', namespace: mailtrainConfig.user.namespace }; this.supplyDefaults(data); this.populateFormValues(data); } } localValidateFormValues(state) { const t = this.props.t; if (!state.getIn(['name', 'value'])) { state.setIn(['name', 'error'], t('nameMustNotBeEmpty')); } else { state.setIn(['name', 'error'], null); } validateNamespace(t, state); let formsServerValidationRunning = false; const formsErrors = []; for (const fld of this.serverValidatedFields) { const serverValidation = state.getIn([fld, 'serverValidation']); if (serverValidation && serverValidation.errors) { formsErrors.push(...serverValidation.errors.map(x =>
{this.templateSettings[fld].label}{' '}–{' '}{x}
)); } else if (!serverValidation) { formsServerValidationRunning = true; } } if (!formsErrors.length && formsServerValidationRunning) { formsErrors.push(t('validationIsInProgress')); } if (formsErrors.length) { state.setIn(['selectedTemplate', 'error'],
{t('listOfErrorsInTemplates') + ':'}
); } else { state.setIn(['selectedTemplate', 'error'], null); } } @withFormErrorHandlers async submitHandler(submitAndLeave, copy) { const t = this.props.t; let sendMethod, url; if (this.props.entity) { if(copy){ sendMethod = FormSendMethod.POST; url = `rest/forms/${this.props.entity.id}` }else{ sendMethod = FormSendMethod.PUT; url = `rest/forms/${this.props.entity.id}` } } else { sendMethod = FormSendMethod.POST; url = 'rest/forms' } this.disableForm(); this.setFormStatusMessage('info', t('saving')); const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url); if (submitResult) { if (this.props.entity) { if (submitAndLeave) { this.navigateToWithFlashMessage('/lists/forms', 'success', t('customFormsUpdated')); } else { await this.getFormValuesFromURL(`rest/forms/${this.props.entity.id}`); this.enableForm(); if(copy){ this.navigateToWithFlashMessage(`/lists/forms`, 'success', t('customFormsCopied')); }else{ this.setFormStatusMessage('success', t('customFormsUpdated')); } } } else { if (submitAndLeave) { this.navigateToWithFlashMessage('/lists/forms', 'success', t('customFormsCreated')); } else { if(copy){ this.navigateToWithFlashMessage(`/lists/forms`, 'success', t('customFormsCopied')); }else{ this.navigateToWithFlashMessage(`/lists/forms/${submitResult}/edit`, 'success', t('customFormsCreated')); } } } } else { this.enableForm(); this.setFormStatusMessage('warning', t('thereAreErrorsInTheFormPleaseFixThemAnd')); } } async preview(formKey) { const data = { formKey, template: this.getFormValue(formKey), layout: this.getFormValue('layout'), formInputStyle: this.getFormValue('form_input_style'), listId: this.getFormValue('previewList') } const response = await axios.post(getUrl('rest/forms-preview'), data); this.setState({ previewKey: formKey, previewContents: response.data.content, previewLabel: this.templateSettings[formKey].label }); } render() { const t = this.props.t; const isEdit = !!this.props.entity; const canDelete = isEdit && this.props.entity.permissions.includes('delete'); const templateOptGroups = []; for (const grpKey in this.templateGroups) { const grp = this.templateGroups[grpKey]; templateOptGroups.push({ key: grpKey, label: grp.label, options: grp.options.map(opt => ({ key: opt, label: this.templateSettings[opt].label })) }); } const listsColumns = [ { data: 0, title: "#" }, { data: 1, title: t('name') }, { data: 2, title: t('id'), render: data => {data} }, { data: 5, title: t('namespace') } ]; const previewListId = this.getFormValue('previewList'); const selectedTemplate = this.getFormValue('selectedTemplate'); return (
{canDelete && } {isEdit ? t('editCustomForms') : t('createCustomForms')}