Skip to content

Commit

Permalink
Basic search and select gif from Giphy
Browse files Browse the repository at this point in the history
  • Loading branch information
donmhico committed Mar 4, 2020
1 parent cc6abb0 commit 151636e
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 23 deletions.
25 changes: 17 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,8 @@
},
"devDependencies": {
"@wordpress/scripts": "^7.1.2"
},
"dependencies": {
"react-photo-gallery": "^8.0.0"
}
}
59 changes: 59 additions & 0 deletions src/components/SearchGiphy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { Component, Fragment } from '@wordpress/element';
import { TextControl, Spinner } from '@wordpress/components';
import Gallery from "react-photo-gallery";

export default class SearchGiphy extends Component {
constructor(props) {
super(props);
}

render() {
const {
search,
onSearchChangeHandler,
isLoading,
gifs,
onGiphyClick,
pagination
} = this.props;

let result_gifs;
if ( gifs[ pagination ] ) {
result_gifs = [];
result_gifs = gifs[ pagination ].map( ( gif_data ) => {
return {
src: gif_data.images.downsized_medium.url,
width: gif_data.images.downsized_medium.width,
height: gif_data.images.downsized_medium.height,
};
} )
}

return (
<Fragment>
<TextControl
label="Search GIF"
value={ search }
onChange={ ( search ) => {
onSearchChangeHandler( search );
} }
/>

{ isLoading && (
<Spinner />
) }

{ result_gifs && result_gifs.length && (
<Fragment>
<Gallery photos={ result_gifs } onClick={ onGiphyClick } />
</Fragment>
) }

{ result_gifs && result_gifs.length === 0 && (
<p>{ `Nothing found for '${search}'.` }</p>
) }

</Fragment>
);
}
}
141 changes: 133 additions & 8 deletions src/edit.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,146 @@
import { Component } from '@wordpress/element';
import { TextControl } from '@wordpress/components';
import { AlignmentToolbar, BlockControls, BlockAlignmentToolbar } from '@wordpress/editor';
import { addQueryArgs } from '@wordpress/url';
import { debounce } from 'lodash';

import SearchGiphy from "./components/SearchGiphy";

export default class Edit extends Component {
constructor( props ) {
super( props );

this.state = {
isLoading: false, // If currently fetching from Giphy.
isSearching: !props.attributes.gif, // If we need to show the search field.
gifs: [], // Cache results from Giphy.
pagination: 0, // Current pagination.
};

// Get the API Key from https://developers.giphy.com/.
this.API_KEY = '[INSERT YOUR API KEY HERE]';
this.GIPHY_ENDPOINT = 'https://api.giphy.com/v1/gifs/search';
this.GIPHY_RESULTS_LIMIT = 5;

this.onSearchChangeHandler = this.onSearchChangeHandler.bind( this );
this.fetchGiphy = this.fetchGiphy.bind( this );
// Use debounce to prevent multiple concurrent request to Giphy.
this.onSearchChange = debounce( this.onSearchChange.bind( this ), 500 );
this.onGiphyClick = this.onGiphyClick.bind( this );
}

componentWillUnmount() {
this.onSearchChange.cancel();
}

/**
* Debounced function
*
* @returns {Promise<void>}
*/
async onSearchChange() {
const {
attributes: { search }
} = this.props;

const pagination = this.state.pagination / this.GIPHY_RESULTS_LIMIT;

const results = await this.fetchGiphy( search, pagination );

if ( 200 !== results.meta.status ) {
// TODO handle error.
return;
}

// The idea is to 'cache' the past results in the state.
// Something like
// gifs[0] => Will contain results of pagination 0.
// gifs[1] => Results of pagination 1.
// and so on..
let gifs = this.state.gifs;
gifs[ pagination ] = results.data;

this.setState( {
isLoading: false,
pagination: pagination,
gifs: gifs
} );
}

/**
* Fetch data from Giphy.
*
* @param search string
* @param pagination int
*
* @returns {Promise<any>}
*/
fetchGiphy( search, pagination ) {
// Build the request url.
const requestUrl = addQueryArgs( this.GIPHY_ENDPOINT, {
q: search,
limit: this.GIPHY_RESULTS_LIMIT,
api_key: this.API_KEY,
offset: pagination,
} );

return fetch( requestUrl )
.then( data => data.json() )
.catch( error => error );
};

onGiphyClick( event, { photo } ) {
// Save the selected photo data as `gif` in the DB.
this.props.setAttributes( { gif: photo } );
this.setState( { isSearching: false } );
}

onSearchChangeHandler( search ) {
this.setState( { isLoading: true } );
// Save the search keyword as `search` in the DB.
this.props.setAttributes( { search } );
this.onSearchChange();
}

render() {
const {
attributes: {
search
search,
gif,
blockAlignment,
textAlignment
},
setAttributes,
className,
setAttributes
} = this.props;

const { isLoading, isSearching, gifs, pagination } = this.state;

return (
<TextControl
label="Search GIF"
value={ search }
onChange={ search => setAttributes( { search } )}
/>
<div className={ className }>
<BlockControls>
<BlockAlignmentToolbar
value={ blockAlignment }
onChange={ blockAlignment => setAttributes( { blockAlignment } ) }
/>
<AlignmentToolbar
value={ textAlignment }
onChange={ textAlignment => setAttributes( { textAlignment } ) }
/>
</BlockControls>

{ isSearching ? (
<SearchGiphy
search={ search }
onSearchChangeHandler={ this.onSearchChangeHandler }
isLoading={ isLoading }
gifs={ gifs }
onGiphyClick={ this.onGiphyClick }
pagination={ pagination }
/>
) : (
<img src={ gif.src } />
) }
</div>
);
}
}
24 changes: 17 additions & 7 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,23 @@ registerBlockType( 'create-block/giphy-block', {
icon: 'smiley',

attributes: {
textAlignment: {
type: 'string',
},
blockAlignment: {
type: 'string',
default: 'wide',
},
search: {
type: 'string'
},
gif: {
type: 'object'
}
},
getEditWrapperProps( { blockAlignment } ) {
if ( 'left' === blockAlignment || 'right' === blockAlignment || 'full' === blockAlignment ) {
return { 'data-align': blockAlignment };
}
},

Expand Down Expand Up @@ -81,14 +96,9 @@ registerBlockType( 'create-block/giphy-block', {
*
* @return {WPElement} Element to render.
*/
save() {
save: props => {
return (
<p>
{ __(
'Giphy Block – hello from the saved content!',
'create-block'
) }
</p>
<img src={ props.attributes.gif.src } />
);
},
} );

0 comments on commit 151636e

Please sign in to comment.