diff options
Diffstat (limited to 'plugins/jetpack/extensions/blocks/contact-form/components/jetpack-contact-form.js')
-rw-r--r-- | plugins/jetpack/extensions/blocks/contact-form/components/jetpack-contact-form.js | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/plugins/jetpack/extensions/blocks/contact-form/components/jetpack-contact-form.js b/plugins/jetpack/extensions/blocks/contact-form/components/jetpack-contact-form.js new file mode 100644 index 00000000..952a3934 --- /dev/null +++ b/plugins/jetpack/extensions/blocks/contact-form/components/jetpack-contact-form.js @@ -0,0 +1,266 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; +import emailValidator from 'email-validator'; +import { __, sprintf } from '@wordpress/i18n'; +import { Button, PanelBody, Path, Placeholder, TextControl } from '@wordpress/components'; +import { Component, Fragment } from '@wordpress/element'; +import { compose, withInstanceId } from '@wordpress/compose'; +import { InnerBlocks, InspectorControls } from '@wordpress/editor'; + +/** + * Internal dependencies + */ +import HelpMessage from '../../../shared/help-message'; +import renderMaterialIcon from '../../../shared/render-material-icon'; +import SubmitButton from '../../../shared/submit-button'; + +const ALLOWED_BLOCKS = [ + 'jetpack/markdown', + 'core/paragraph', + 'core/image', + 'core/heading', + 'core/gallery', + 'core/list', + 'core/quote', + 'core/shortcode', + 'core/audio', + 'core/code', + 'core/cover', + 'core/file', + 'core/html', + 'core/separator', + 'core/spacer', + 'core/subhead', + 'core/table', + 'core/verse', + 'core/video', +]; + +class JetpackContactForm extends Component { + constructor( ...args ) { + super( ...args ); + 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.onFormSettingsSet = this.onFormSettingsSet.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 ); + + const to = args[ 0 ].attributes.to ? args[ 0 ].attributes.to : ''; + const error = to + .split( ',' ) + .map( this.getToValidationError ) + .filter( Boolean ); + + this.state = { + toError: error && error.length ? error : null, + }; + } + + getIntroMessage() { + return __( + 'You’ll receive an email notification each time someone fills out the form. Where should it go, and what should the subject line be?', + 'jetpack' + ); + } + + getEmailHelpMessage() { + return __( 'You can enter multiple email addresses separated by commas.', 'jetpack' ); + } + + 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 } ); + return; + } + } + + 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 } ); + } + + onFormSettingsSet( event ) { + event.preventDefault(); + if ( this.state.toError ) { + // don't submit the form if there are errors. + return; + } + this.props.setAttributes( { hasFormSettingsSet: 'yes' } ); + } + + getfieldEmailError( errors ) { + if ( errors ) { + if ( errors.length === 1 ) { + if ( errors[ 0 ] && errors[ 0 ].email ) { + return sprintf( __( '%s is not a valid email address.', 'jetpack' ), errors[ 0 ].email ); + } + return errors[ 0 ]; + } + + if ( errors.length === 2 ) { + return sprintf( + __( '%s and %s are not a valid email address.', 'jetpack' ), + errors[ 0 ].email, + errors[ 1 ].email + ); + } + const inValidEmails = errors.map( error => error.email ); + return sprintf( + __( '%s are not a valid email address.', 'jetpack' ), + inValidEmails.join( ', ' ) + ); + } + return null; + } + + preventEnterSubmittion( event ) { + if ( event.key === 'Enter' ) { + event.preventDefault(); + event.stopPropagation(); + } + } + + 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', 'jetpack' ) } + placeholder={ __( 'name@example.com', 'jetpack' ) } + onKeyDown={ this.preventEnterSubmittion } + value={ to } + onBlur={ this.onBlurTo } + onChange={ this.onChangeTo } + /> + <HelpMessage isError id={ `contact-form-${ instanceId }-email-error` }> + { this.getfieldEmailError( fieldEmailError ) } + </HelpMessage> + <HelpMessage id={ `contact-form-${ instanceId }-email-help` }> + { this.getEmailHelpMessage() } + </HelpMessage> + + <TextControl + label={ __( 'Email subject line', 'jetpack' ) } + value={ subject } + placeholder={ __( "Let's work together", 'jetpack' ) } + onChange={ this.onChangeSubject } + /> + </Fragment> + ); + } + + hasEmailError() { + const fieldEmailError = this.state.toError; + return fieldEmailError && fieldEmailError.length > 0; + } + + render() { + const { className, attributes } = this.props; + const { hasFormSettingsSet } = attributes; + const formClassnames = classnames( className, 'jetpack-contact-form', { + 'has-intro': ! hasFormSettingsSet, + } ); + + return ( + <Fragment> + <InspectorControls> + <PanelBody title={ __( 'Email feedback settings', 'jetpack' ) }> + { this.renderToAndSubjectFields() } + </PanelBody> + </InspectorControls> + <div className={ formClassnames }> + { ! hasFormSettingsSet && ( + <Placeholder + label={ __( 'Form', 'jetpack' ) } + icon={ renderMaterialIcon( + <Path d="M13 7.5h5v2h-5zm0 7h5v2h-5zM19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V5h14v14zM11 6H6v5h5V6zm-1 4H7V7h3v3zm1 3H6v5h5v-5zm-1 4H7v-3h3v3z" /> + ) } + > + <form onSubmit={ this.onFormSettingsSet }> + <p className="jetpack-contact-form__intro-message">{ this.getIntroMessage() }</p> + { this.renderToAndSubjectFields() } + <p className="jetpack-contact-form__intro-message"> + { __( + '(If you leave these blank, notifications will go to the author with the post or page title as the subject line.)', + 'jetpack' + ) } + </p> + <div className="jetpack-contact-form__create"> + <Button isPrimary type="submit" disabled={ this.hasEmailError() }> + { __( 'Add form', 'jetpack' ) } + </Button> + </div> + </form> + </Placeholder> + ) } + { hasFormSettingsSet && ( + <InnerBlocks + allowedBlocks={ ALLOWED_BLOCKS } + templateLock={ false } + template={ [ + [ + 'jetpack/field-name', + { + required: true, + }, + ], + [ + 'jetpack/field-email', + { + required: true, + }, + ], + [ 'jetpack/field-url', {} ], + [ 'jetpack/field-textarea', {} ], + ] } + /> + ) } + { hasFormSettingsSet && <SubmitButton { ...this.props } /> } + </div> + </Fragment> + ); + } +} + +export default compose( [ withInstanceId ] )( JetpackContactForm ); |