Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experience Blocks #24

Merged
merged 44 commits into from
Jun 5, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
7507d69
First draft experience blocks
roborourke May 11, 2020
ad4bf72
add eslint and fix code style issues
roborourke May 12, 2020
bc20304
record an event when an XB is viewed
roborourke May 12, 2020
beea777
Fix nodelist iterator
roborourke May 12, 2020
07dc288
Web components cannot be self closing
roborourke May 12, 2020
7dc8b51
Fix positioning of the audience picker component
roborourke May 12, 2020
de274dc
Test load experiments.js async
roborourke May 13, 2020
214d516
remove URLInput in favour of UI from main analytics plugin
roborourke May 14, 2020
8965c19
Adding UI polish plus copy function
roborourke May 16, 2020
2ea9fb5
fix white space error
roborourke May 16, 2020
6110a33
switch to using webpack manifest plugin
roborourke May 18, 2020
f5e6834
Fix initial XB insert logic, innerBlocks template wasnt working
roborourke May 18, 2020
bb0b6e5
Support for using audience names or fallback for variant
roborourke May 18, 2020
5589659
fix linter errors
roborourke May 18, 2020
19ee037
Dont uppercase the XB header
roborourke May 18, 2020
67c2db3
Ensure custom elements are only defined when analytics.js has loaded
roborourke May 18, 2020
0fe1fa2
expose `Test.registerGoal` before defining custom elements
roborourke May 18, 2020
80b8b23
Ensure BuildURL is defined for file chunks
roborourke May 18, 2020
73b2a7f
Add missing docblocks and fix use statements
roborourke May 20, 2020
5366588
rename block to personalized content and add XB block category
roborourke May 22, 2020
d75ce8f
Improve personalised content block header styling for dark backgrounds
roborourke May 22, 2020
624fbac
Bind setContent to the current instance
rmccue May 27, 2020
3905c75
Merge pull request #27 from humanmade/bind-setcontent
roborourke May 27, 2020
bedb416
Use explicit fallback block that cannot be removed
roborourke May 28, 2020
d503042
compare `json_last_error()` to `JSON_ERROR_NONE` constant
roborourke May 29, 2020
371ccf8
Pre fetch posts and only re-render XB when isLoading changes
roborourke May 29, 2020
f04b669
Merge branch 'experience-blocks' of github.com:humanmade/experiments …
roborourke May 29, 2020
a38ed58
Use component for rendering variant title
roborourke May 29, 2020
588d445
Code review improvements
roborourke Jun 1, 2020
5e20d29
Commit new component files
roborourke Jun 1, 2020
f6db732
Check if audience is set on client side rather than fallback var
roborourke Jun 1, 2020
a7f54ae
Add missing semi colons
roborourke Jun 1, 2020
50b5d2f
Fix operator spacing
roborourke Jun 1, 2020
ea18161
Check for error on audience object in VariantTitle
roborourke Jun 1, 2020
4d038a3
Use plugin file constant for `plugins_url()` calls
roborourke Jun 1, 2020
d421491
Check audience status for `trash` as well API error
roborourke Jun 1, 2020
73b10f5
Rename callback to be prefixed with `on*`
roborourke Jun 3, 2020
bc7e45e
Fix styling for WP 5.4
roborourke Jun 3, 2020
f064ad8
Fix flexbox toolbar issues
roborourke Jun 3, 2020
218e43c
Merge master
roborourke Jun 4, 2020
d1514b0
Fix minor coding standards pieces
rmccue Jun 4, 2020
ac81eca
Simplify some tidbits
rmccue Jun 4, 2020
ddc9dd0
Correct a misspellling
rmccue Jun 4, 2020
e59f4fc
Use ROOT_FILE for title ab test asset URL
roborourke Jun 5, 2020
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
17 changes: 17 additions & 0 deletions inc/features/blocks/experience/block.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "altis/experience-block",
"settings": {
"category": "layout",
roborourke marked this conversation as resolved.
Show resolved Hide resolved
"icon": "lightbulb",
"supports": {
"alignWide": true,
"html": false,
"align": true
},
"attributes": {
"clientId": {
"type": "string"
}
}
}
}
131 changes: 131 additions & 0 deletions inc/features/blocks/experience/components/AudiencePicker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import React, { useState, useEffect } from 'react';
import URLInput from './URLInput';

const { apiFetch } = wp;
const { Button } = wp.components;
const { decodeEntities } = wp.htmlEntities;
const { __ } = wp.i18n;
const { addQueryArgs } = wp.url;

/**
* Fetches link suggestions from the API. This function is an exact copy of a function found at:
*
* wordpress/editor/src/components/provider/index.js
*
* @param {Object} search
* @param {number} perPage
* @return {Promise<Object[]>} List of suggestions
*/
const fetchSuggestions = async ( search, { perPage = 20 } = {} ) => {
const posts = await apiFetch( {
path: addQueryArgs( '/wp/v2/audiences', {
search,
per_page: perPage,
status: 'publish',
} ),
} );

return posts.map( post => ( {
id: post.id,
title: decodeEntities( post.title.rendered ) || __( '(no title)' ),
url: '',
} ) );
};

/**
* Fetch a single audience by ID.
*
* @param {number} id An audience post ID.
* @param {Function} callback An optional callback that receives the audience object.
* @return {Promise<Object>} Audience post object.
*/
const fetchAudience = async ( id, callback ) => {
const post = await apiFetch( {
path: `/wp/v2/audiences/${ id }`
} );

const audience = {
id: post.id,
title: decodeEntities( post.title.rendered ) || __( '(no title)' ),
audience: post.audience,
status: post.status,
};

// Allow for easy use with useEffect.
callback && callback( audience );

return audience;
}

const AudiencePicker = props => {
const [ value, setValue ] = useState( '' );
const [ selectedAudience, setAudience ] = useState( null );

// If we have an ID and no value trigger a fetch of the audience object so
// that external components can access the audience post data.
useEffect( () => {
if ( ! props.audience || value !== '' ) {
return;
}

fetchAudience( props.audience, audience => {
setAudience( audience );
props.onSelect( audience );
} );
}, [ props.audience ] );

return (
<URLInput
className="audience-picker-control"
label={ props.label || '' }
autoFocus={ props.autoFocus || false }
placeholder={ props.placeholder || __( 'Search audiences', 'altis-experiments' ) }
isFullWidth={ true }
hasBorder={ true }
__experimentalFetchLinkSuggestions={ fetchSuggestions }
fetchLinkSuggestions={ fetchSuggestions }
value={ value }
onChange={ ( text, audience ) => {
// Only update the input value when we don't receive a post object.
if ( ! audience ) {
setValue( text );
}

// Trigger select event if we receive a post object.
if ( audience ) {
setAudience( audience );
if ( props.onSelect ) {
props.onSelect( audience );
}
}
} }
>
{ selectedAudience && (
<p className="audience-picker-control__value">
<strong>{ __( 'Current:' ) }</strong>
{ ' ' }
<span>{ selectedAudience.title }</span>
</p>
) }
{ props.audience && (
<Button
isLink
isDestructive
onClick={ () => {
setValue( '' );
setAudience( null );

// Allow clearing the value.
if ( props.onClearSelection ) {
props.onClearSelection();
}
} }
>
{ __( 'Clear selection' ) }
</Button>
) }
</URLInput>
);
}

export default AudiencePicker;
Loading