Path : /home/vishqocm/vjmedia.in/wp-content/plugins/coblocks/src/blocks/form/
File Upload :
Current File : /home/vishqocm/vjmedia.in/wp-content/plugins/coblocks/src/blocks/form/edit.js

/*global coblocksBlockData*/

/**
 * External dependencies
 */
import classnames from 'classnames';
import emailValidator from 'email-validator';

/**
 * Internal dependencies
 */
import icons from './icons';
import CoBlocksField from './components/fields/field';
import CoBlocksFieldName from './components/fields/field-name';
import CoBlocksFieldTextarea from './components/fields/field-textarea';
import Notice from './components/notice';
import SubmitButton from './components/submit-button';

/**
 * WordPress dependencies
 */
const { __, sprintf } = wp.i18n;
const { Component, Fragment } = wp.element;
const { registerBlockType, getBlockType } = wp.blocks;
const { Button, PanelBody, TextControl, ExternalLink } = wp.components;
const { InspectorControls, InnerBlocks } = wp.blockEditor;
const { applyFilters } = wp.hooks;

/**
 * Block constants
 */
const ALLOWED_BLOCKS = [];

const FieldDefaults = {
	category: 'coblocks',
	parent: [ 'coblocks/form' ],
	supports: {
		reusable: false,
		html: false,
		inserter: false,
	},
	attributes: {
		label: {
			type: 'string',
			default: null,
		},
		required: {
			type: 'boolean',
			default: false,
		},
		hasLastName: {
			type: 'boolean',
			default: false,
		},
		labelFirstName: {
			type: 'string',
			default: __( 'First' ),
		},
		labelLastName: {
			type: 'string',
			default: __( 'Last' ),
		},
	},
	save: () => null,
};

const getFieldLabel = ( { attributes, name: blockName } ) => {
	return null === attributes.label ?
		getBlockType( blockName ).title :
		attributes.label;
};

const editField = type => props => (
	<CoBlocksField
		type={ type }
		label={ getFieldLabel( props ) }
		required={ props.attributes.required }
		setAttributes={ props.setAttributes }
		isSelected={ props.isSelected }
	/>
);

export const childBlocks = [
	{
		name: 'field-name',
		settings: {
			...FieldDefaults,
			title: __( 'Name' ),
			description: __( 'A text field for names.' ),
			icon: icons.name,
			edit: props => (
				<CoBlocksFieldName
					type={ 'name' }
					label={ getFieldLabel( props ) }
					labelFirstName={ props.attributes.labelFirstName }
					labelLastName={ props.attributes.labelLastName }
					required={ props.attributes.required }
					hasLastName={ props.attributes.hasLastName }
					setAttributes={ props.setAttributes }
					isSelected={ props.isSelected }
				/>
			),
		},
	},
	{
		name: 'field-email',
		settings: {
			...FieldDefaults,
			title: __( 'Email' ),
			keywords: [ __( 'e-mail' ), __( 'mail' ), 'email' ],
			description: __( 'An email address field.' ),
			icon: icons.email,
			edit: editField( 'email' ),
		},
	},
	{
		name: 'field-textarea',
		settings: {
			...FieldDefaults,
			title: __( 'Message' ),
			keywords: [ __( 'Textarea' ), 'textarea', __( 'Multiline text' ) ],
			description: __( 'A text box for longer responses.' ),
			icon: icons.textarea,
			edit: props => (
				<CoBlocksFieldTextarea
					label={ getFieldLabel( props ) }
					required={ props.attributes.required }
					setAttributes={ props.setAttributes }
					isSelected={ props.isSelected }
				/>
			),
		},
	},
];

childBlocks.forEach( childBlock =>
	registerBlockType( `coblocks/${ childBlock.name }`, childBlock.settings )
);

/**
 * Get settings
 */
let settings;
wp.api.loadPromise.then( () => {
	settings = new wp.api.models.Settings();
} );

const FORM_TEMPLATE = [
	[
		'coblocks/field-name',
		{
			required: false,
		},
	],
	[
		'coblocks/field-email',
		{
			required: true,
		},
	],
	[
		'coblocks/field-textarea',
		{
			required: true,
		},
	],
];

const RETRIEVE_KEY_URL = 'https://g.co/recaptcha/v3';
const HELP_URL = 'https://developers.google.com/recaptcha/docs/v3';

class FormEdit extends Component {
	constructor() {
		super( ...arguments );

		this.onChangeSubject = this.onChangeSubject.bind( this );
		this.onBlurTo = this.onBlurTo.bind( this );
		this.onChangeTo = this.onChangeTo.bind( this );
		this.onChangeSubmit = this.onChangeSubmit.bind( this );
		this.getToValidationError = this.getToValidationError.bind( this );
		this.renderToAndSubjectFields = this.renderToAndSubjectFields.bind( this );
		this.preventEnterSubmittion = this.preventEnterSubmittion.bind( this );
		this.hasEmailError = this.hasEmailError.bind( this );
		this.saveRecaptchaKey = this.saveRecaptchaKey.bind( this );
		this.removeRecaptchaKey = this.removeRecaptchaKey.bind( this );

		this.state = {
			toError: error && error.length ? error : null,
			siteKey: '',
			isSavedKey: false,
			isSaving: false,
			keySaved: false,
		};

		const to = arguments[ 0 ].attributes.to ? arguments[ 0 ].attributes.to : '';
		const error = to
			.split( ',' )
			.map( this.getToValidationError )
			.filter( Boolean );

		settings.on( 'change:coblocks_google_recaptcha_site_key', model => {
			const recaptchaSiteKey = model.get( 'coblocks_google_recaptcha_site_key' );
			this.setState( {
				recaptchaSiteKey: settings.get( 'coblocks_google_recaptcha_site_key' ),
				isSavedKey: recaptchaSiteKey === '' ? false : true,
			} );
		} );

		settings.on( 'change:coblocks_google_recaptcha_secret_key', model => {
			const recaptchaSecretKey = model.get(
				'coblocks_google_recaptcha_secret_key'
			);
			this.setState( {
				recaptchaSecretKey: settings.get(
					'coblocks_google_recaptcha_secret_key'
				),
				isSavedKey: recaptchaSecretKey === '' ? false : true,
			} );
		} );

		settings.fetch().then( response => {
			this.setState( {
				recaptchaSiteKey: response.coblocks_google_recaptcha_site_key,
			} );
			if ( this.state.recaptchaSiteKey && this.state.recaptchaSiteKey !== '' ) {
				this.setState( { isSavedKey: true } );
			}
		} );

		settings.fetch().then( response => {
			this.setState( {
				recaptchaSecretKey: response.coblocks_google_recaptcha_secret_key,
			} );
			if (
				this.state.recaptchaSecretKey &&
				this.state.recaptchaSecretKey !== ''
			) {
				this.setState( { isSavedKey: true } );
			}
		} );
	}

	onChangeSubject( subject ) {
		this.props.setAttributes( { subject } );
	}

	getToValidationError( email ) {
		email = email.trim();
		if ( email.length === 0 ) {
			return false; // ignore the empty emails
		}
		if ( ! emailValidator.validate( email ) ) {
			return { email };
		}
		return false;
	}

	onBlurTo( event ) {
		const error = event.target.value
			.split( ',' )
			.map( this.getToValidationError )
			.filter( Boolean );
		if ( error && error.length ) {
			this.setState( { toError: error } );
		}
	}

	onChangeTo( to ) {
		const emails = to.trim();
		if ( emails.length === 0 ) {
			this.setState( { toError: null } );
			this.props.setAttributes( { to } );
			return;
		}

		this.setState( { toError: null } );
		this.props.setAttributes( { to } );
	}

	onChangeSubmit( submitButtonText ) {
		this.props.setAttributes( { submitButtonText } );
	}

	getfieldEmailError( errors ) {
		if ( errors ) {
			if ( errors.length === 1 ) {
				if ( errors[ 0 ] && errors[ 0 ].email ) {
					return sprintf(
						__( '%s is not a valid email address.' ),
						errors[ 0 ].email
					);
				}
				return errors[ 0 ];
			}

			if ( errors.length === 2 ) {
				return sprintf(
					__( '%s and %s are not a valid email address.' ),
					errors[ 0 ].email,
					errors[ 1 ].email
				);
			}
			const inValidEmails = errors.map( error => error.email );
			return sprintf(
				__( '%s are not a valid email address.' ),
				inValidEmails.join( ', ' )
			);
		}
		return null;
	}

	preventEnterSubmittion( event ) {
		if ( event.key === 'Enter' ) {
			event.preventDefault();
			event.stopPropagation();
		}
	}

	saveRecaptchaKey() {
		this.setState( { isSaving: true } );

		const model = new wp.api.models.Settings( {
			coblocks_google_recaptcha_site_key: this.state.recaptchaSiteKey,
			coblocks_google_recaptcha_secret_key: this.state.recaptchaSecretKey,
		} );
		model.save().then( () => {
			this.setState( { isSavedKey: true, keySaved: true } );
			setTimeout( () => {
				this.setState( { isSaving: false } );
			}, 1000 );
			settings.fetch();
		} );
	}

	removeRecaptchaKey() {
		this.setState( {
			recaptchaSiteKey: '',
			recaptchaSecretKey: '',
		} );
		if ( this.state.isSavedKey ) {
			this.setState( { isSaving: true } );
			const model = new wp.api.models.Settings( {
				coblocks_google_recaptcha_site_key: '',
				coblocks_google_recaptcha_secret_key: '',
			} );
			model.save().then( () => {
				this.setState( { isSavedKey: false, isSaving: false, keySaved: false } );
				settings.fetch();
			} );
		}
	}

	renderToAndSubjectFields() {
		const fieldEmailError = this.state.toError;
		const { instanceId, attributes } = this.props;
		const { subject, to } = attributes;
		return (
			<Fragment>
				<TextControl
					aria-describedby={ `contact-form-${ instanceId }-email-${
						this.hasEmailError() ? 'error' : 'help'
					}` }
					label={ __( 'Email address' ) }
					placeholder={ __( '[email protected]' ) }
					onKeyDown={ this.preventEnterSubmittion }
					value={ to || '' === to ? to : coblocksBlockData.form.adminEmail }
					onBlur={ this.onBlurTo }
					onChange={ this.onChangeTo }
				/>
				<Notice isError id={ `contact-form-${ instanceId }-email-error` }>
					{ this.getfieldEmailError( fieldEmailError ) }
				</Notice>
				<TextControl
					label={ __( 'Subject' ) }
					value={
						subject || '' === subject ?
							subject :
							coblocksBlockData.form.emailSubject
					}
					onChange={ this.onChangeSubject }
				/>
			</Fragment>
		);
	}

	hasEmailError() {
		const fieldEmailError = this.state.toError;
		return fieldEmailError && fieldEmailError.length > 0;
	}

	render() {
		const {
			className,
		} = this.props;

		const classes = classnames(
			className,
			'coblocks-form',
		);

		return (
			<Fragment>
				<InspectorControls>
					<PanelBody title={ __( 'Form Settings' ) }>
						{ this.renderToAndSubjectFields() }
						{ applyFilters( 'coblocks.advanced_forms_cta' ) }
					</PanelBody>
					<PanelBody
						title={ __( 'Google reCAPTCHA' ) }
						initialOpen={ this.state.recaptchaSecretKey ? false : true }
					>
						<p>{ __( 'Add your reCAPTCHA site and secret keys to protect your form from spam.' ) }</p>
						<p>
							<Fragment>
								<ExternalLink href={ RETRIEVE_KEY_URL }>
									{ this.state.recaptchaSiteKey === '' &&
									this.state.recaptchaSecretKey === '' ?
										__( 'Generate keys' ) :
										__( 'My keys' ) }
								</ExternalLink>
								|&nbsp;
								<ExternalLink href={ HELP_URL }>{ __( 'Get help' ) }</ExternalLink>
							</Fragment>
						</p>
						<TextControl
							label={ __( 'Site Key' ) }
							value={ this.state.recaptchaSiteKey }
							onChange={ value => this.setState( { recaptchaSiteKey: value } ) }
							className="components-block-coblocks-form-recaptcha-key__custom-input"
						/>
						<TextControl
							label={ __( 'Secret Key' ) }
							value={ this.state.recaptchaSecretKey }
							onChange={ value => this.setState( { recaptchaSecretKey: value } ) }
							className="components-block-coblocks-form-recaptcha-key__custom-input"
						/>
						<div className="components-base-control components-block-coblocks-form-recaptcha-buttons">
							<Button
								isPrimary
								onClick={ this.saveRecaptchaKey }
								disabled={
									this.state.recaptchaSiteKey === '' ||
									this.state.recaptchaSecretKey === ''
								}
							>
								{ this.state.isSaving ? __( 'Saving' ) : __( 'Save' ) }
							</Button>
							{ this.state.recaptchaSiteKey !== '' &&
								this.state.recaptchaSecretKey !== '' && (
								<Fragment>
										&nbsp;
									<Button
										className="components-block-coblocks-form-recaptcha-key-remove__button"
										isDefault
										onClick={ this.removeRecaptchaKey }
										disabled={
											this.state.recaptchaSiteKey === '' ||
												this.state.recaptchaSecretKey === ''
										}
									>
										{ __( 'Remove' ) }
									</Button>
								</Fragment>
							) }
						</div>
					</PanelBody>
				</InspectorControls>
				<div className={ classes }>
					<InnerBlocks
						allowedBlocks={ ALLOWED_BLOCKS }
						templateLock={ true }
						templateInsertUpdatesSelection={ false }
						renderAppender={ () => null }
						template={ FORM_TEMPLATE }
					/>
					<SubmitButton { ...this.props } />
				</div>
			</Fragment>
		);
	}
}

export default FormEdit;