Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 36 additions & 5 deletions extensions/blocks/calendly/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ import {
Notice,
PanelBody,
Placeholder,
Spinner,
ToggleControl,
Toolbar,
withNotices,
} from '@wordpress/components';
import { useState } from '@wordpress/element';
import { useEffect, useState } from '@wordpress/element';
import { __, _x } from '@wordpress/i18n';
import { getBlockDefaultClassName } from '@wordpress/blocks';

Expand All @@ -34,6 +35,8 @@ import { getValidatedAttributes } from '../../shared/get-validated-attributes';
import SubmitButton from '../../shared/submit-button';
import { getAttributesFromEmbedCode } from './utils';
import BlockStylesSelector from '../../shared/components/block-styles-selector';
import { CALENDLY_EXAMPLE_URL } from './';
import testEmbedUrl from '../../shared/test-embed-url';

function CalendlyEdit( props ) {
const {
Expand Down Expand Up @@ -62,6 +65,7 @@ function CalendlyEdit( props ) {
url,
} = validatedAttributes;
const [ embedCode, setEmbedCode ] = useState( '' );
const [ isResolvingUrl, setIsResolvingUrl ] = useState( false );

const setErrorNotice = () => {
noticeOperations.removeAllNotices();
Expand All @@ -70,6 +74,16 @@ function CalendlyEdit( props ) {
);
};

useEffect( () => {
if ( ! url || CALENDLY_EXAMPLE_URL === url || 'link' === style ) {
return;
}
testEmbedUrl( url, setIsResolvingUrl ).catch( () => {
setAttributes( { url: undefined } );
setErrorNotice();
} );
}, [] );

const parseEmbedCode = event => {
if ( ! event ) {
setErrorNotice();
Expand All @@ -84,10 +98,16 @@ function CalendlyEdit( props ) {
return;
}

const newValidatedAttributes = getValidatedAttributes( attributeDetails, newAttributes );

setAttributes( newValidatedAttributes );
noticeOperations.removeAllNotices();
testEmbedUrl( newAttributes.url, setIsResolvingUrl )
.then( () => {
const newValidatedAttributes = getValidatedAttributes( attributeDetails, newAttributes );
setAttributes( newValidatedAttributes );
noticeOperations.removeAllNotices();
} )
.catch( () => {
setAttributes( { url: undefined } );
setErrorNotice();
} );
};

const embedCodeForm = (
Expand Down Expand Up @@ -115,6 +135,13 @@ function CalendlyEdit( props ) {
</>
);

const blockEmbedding = (
<div className="wp-block-embed is-loading">
<Spinner />
<p>{ __( 'Embedding…', 'jetpack' ) }</p>
</div>
);

const blockPlaceholder = (
<Placeholder
label={ __( 'Calendly', 'jetpack' ) }
Expand Down Expand Up @@ -257,6 +284,10 @@ function CalendlyEdit( props ) {
</InspectorControls>
);

if ( isResolvingUrl ) {
return blockEmbedding;
}

const classes = `${ className } calendly-style-${ style }`;

return (
Expand Down
4 changes: 3 additions & 1 deletion extensions/blocks/calendly/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { getAttributesFromEmbedCode, REGEX } from './utils';
*/
import './editor.scss';

export const CALENDLY_EXAMPLE_URL = 'https://calendly.com/wordpresscom/jetpack-block-example';

export const name = 'calendly';
export const title = __( 'Calendly', 'jetpack' );
export const settings = {
Expand Down Expand Up @@ -44,7 +46,7 @@ export const settings = {
submitButtonText: __( 'Schedule time with me', 'jetpack' ),
hideEventTypeDetails: false,
style: 'inline',
url: 'https://calendly.com/wordpresscom/jetpack-block-example',
url: CALENDLY_EXAMPLE_URL,
},
},
transforms: {
Expand Down
41 changes: 41 additions & 0 deletions extensions/shared/test-embed-url.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* External dependencies
*/
import { noop } from 'lodash';

/**
* WordPress dependencies
*/
import apiFetch from '@wordpress/api-fetch';

/**
* Test if a URL is accessible and respond with status code < 400.
*
* @example
* const [ isResolvingUrl, setIsResolvingUrl ] = useState();
* testEmbedUrl( url, setIsResolvingUrl )
* .then( () => setAttributes( url ) )
* .catch( () => setErrorNotice() );
*
* @param {String} url The URL to test.
* @param {Function} [setIsResolvingUrl=noop] An optional function to track the resolving state. Typically used to update the calling component's state.
* @returns {Promise} Resolve if the URL is valid, reject otherwise.
*/
export default function testEmbedUrl( url, setIsResolvingUrl = noop ) {
setIsResolvingUrl( true );
return new Promise( async ( resolve, reject ) => {
try {
const response = await apiFetch( { path: `/wpcom/v2/resolve-redirect/${ url }` } );
setIsResolvingUrl( false );
const responseStatusCode = response.status ? parseInt( response.status, 10 ) : null;
if ( responseStatusCode && responseStatusCode >= 400 ) {
reject();
} else {
resolve();
}
} catch ( error ) {
setIsResolvingUrl( false );
reject();
}
} );
}