Permalink
Browse files

Move Daily Post button to blocks

  • Loading branch information...
1 parent 0b37030 commit c4f80088582bbec6b33faa860e34383e0ae10360 @bluefuton bluefuton committed Nov 14, 2016
@@ -0,0 +1,14 @@
+# Reader Daily Post
+
+The component wraps a Button and SitesPopover to set up a new post in the editor for a [Daily Post](dailypost.wordpress.com) prompt or challenge.
+
+## Component Props
+
+- `tagName`: a string or ReactComponent, the root rendering component.
+- `position`: string, the SitesPopover position relative to the Button
+- `post`: object, the Daily Post post
+
+
+## Helper
+
+Use the `isDailyPost` helper function to assert the post is from dailypost.wordpress.com.
@@ -0,0 +1,17 @@
+/**
+ * Internal Dependencies
+ */
+import config from 'config';
+
+const types = {
+ dp_prompt: 'prompt',
+ dp_photo_challenge: 'photo',
+ dp_discover: 'discover'
+};
+export function isDailyPostChallengeOrPrompt( post ) {
+ return post.site_ID === config( 'daily_post_blog_id' ) && !! types[ post.type ];
+}
+
+export function getDailyPostType( post ) {
+ return types[ post.type ];
+}
@@ -0,0 +1,181 @@
+/**
+ * External Dependencies
+ */
+import React from 'react';
+import classnames from 'classnames';
+import page from 'page';
+import qs from 'qs';
+import { get, defer } from 'lodash';
+
+/**
+ * Internal Dependencies
+ */
+import { translate } from 'i18n-calypso';
+import { preload } from 'sections-preload';
+import SitesPopover from 'components/sites-popover';
+import Button from 'components/button';
+import Gridicon from 'components/gridicon';
+import { markSeen as markPostSeen } from 'lib/feed-post-store/actions';
+
+import getSitesList from 'lib/sites-list';
+import { recordGaEvent, recordAction, recordTrackForPost } from 'reader/stats';
+import { getDailyPostType } from './helper';
+
+const sitesList = getSitesList();
+
+function getPingbackAttributes( post ) {
+ const typeTitles = {
+ prompt: translate( 'Daily Prompt: ' ),
+ photo: translate( 'Photo Challenge: ' ),
+ discover: translate( 'Discover Challenge: ' )
+ };
+ const title = typeTitles[ getDailyPostType( post ) ] + post.title;
+
+ return {
+ title,
+ url: post.URL
+ };
+}
+
+function preventDefault( event ) {
+ event.preventDefault();
+}
+
+function preloadEditor() {
+ preload( 'post-editor' );
+}
+
+function onlyOneSite() {
+ return sitesList.data.length === 1;
+}
+
+class DailyPostButton extends React.Component {
+ constructor() {
+ super();
+ this.state = {
+ showingMenu: false
+ };
+
+ this._closeTimerId = null;
+ this._isMounted = false;
+
+ [ 'openEditorWithSite', 'toggle', 'closeMenu', 'renderSitesPopover' ].forEach(
+ ( method ) => this[ method ] = this[ method ].bind( this )
+ );
+ }
+
+ static propTypes = {
+ post: React.PropTypes.object.isRequired,
+ position: React.PropTypes.string,
+ tagName: React.PropTypes.string,
+ }
+
+ static defaultProps = {
+ position: 'top',
+ tagName: 'li'
+ }
+
+ componentDidMount() {
+ this._isMounted = true;
+ }
+
+ componentWillUnmount() {
+ this._isMounted = false;
+ if ( this._closeTimerId ) {
+ clearTimeout( this._closeTimerId );
+ this._closeDefer = null;
+ }
+ }
+
+ _deferMenuChange( showingMenu ) {
+ if ( this._closeTimerId ) {
+ clearTimeout( this._closeTimerId );
+ }
+ this._closeTimerId = defer( () => {
+ this._closeTimerId = null;
+ this.setState( { showingMenu } );
+ } );
+ }
+
+ openEditorWithSite( siteSlug ) {
+ const pingbackAttributes = getPingbackAttributes( this.props.post );
+
+ recordAction( 'daily_post_challenge' );
+ recordGaEvent( 'Clicked on Daily Post challenge' );
+ recordTrackForPost( 'calypso_reader_daily_post_challenge_site_picked', this.props.post );
+
+ markPostSeen( this.props.post );
+
+ page( `/post/${ siteSlug }?${ qs.stringify( pingbackAttributes ) }` );
+ return true;
+ }
+
+ toggle( event ) {
+ preventDefault( event );
+ if ( ! this.state.showingMenu ) {
+ recordAction( 'open_daily_post_challenge' );
+ recordGaEvent( 'Opened Daily Post Challenge' );
+ recordTrackForPost( 'calypso_reader_daily_post_challenge_opened', this.props.post );
+
+ if ( onlyOneSite() ) {
+ const primarySlug = get( sitesList.getPrimary(), 'slug' );
+ return this.openEditorWithSite( primarySlug );
+ }
+ }
+ this._deferMenuChange( ! this.state.showingMenu );
+ }
+
+ closeMenu() {
+ // have to defer this to let the mouseup / click escape.
+ // If we don't defer and remove the DOM node on this turn of the event loop,
+ // Chrome (at least) will not fire the click
+ if ( this._isMounted ) {
+ this._deferMenuChange( false );
+ }
+ }
+
+ renderSitesPopover() {
+ return (
+ <SitesPopover
+ key="menu"
+ header={ <div> { translate( 'Post on' ) } </div> }
+ sites={ sitesList }
+ context={ this.refs && this.refs.dailyPostButton }
+ visible={ this.state.showingMenu }
+ groups={ true }
+ onSiteSelect={ this.openEditorWithSite }
+ onClose={ this.closeMenu }
+ position="top"
+ className="is-reader" />
+ );
+ }
+
+ render() {
+ const canParticipate = !! sitesList.getPrimary();
+ const title = get( this.props, 'post.title' );
+ const buttonClasses = classnames( {
+ 'daily-post-button__button': true,
+ 'ignore-click': true,
+ 'is-active': this.state.showingMenu
+ } );
+
+ if ( ! canParticipate ) {
+ return null;
+ }
+
+ return React.createElement( this.props.tagName, {
+ className: 'daily-post-button',
+ onTouchTap: this.toggle,
+ onClick: preventDefault,
+ onTouchStart: preloadEditor,
+ onMouseEnter: preloadEditor
+ }, [
+ ( <Button ref="dailyPostButton" key="button" compact primary className={ buttonClasses }>
+ <Gridicon icon="create" /><span>{ translate( 'Post about %(title)s', { args: { title } } ) } </span>
+ </Button> ),
+ ( this.state.showingMenu ? this.renderSitesPopover() : null )
+ ] );
+ }
+}
+
+export default DailyPostButton;
@@ -0,0 +1,12 @@
+.daily-post-button {
+ margin-top: 20px;
+ display: inline-block;
+
+ .daily-post-button__button {
+ text-transform: capitalize;
+
+ .gridicon {
+ margin-right: 5px;
+ }
+ }
+}
@@ -0,0 +1,41 @@
+
+const dailyPostSiteId = 489937;
+
+export const basicPost = {
+ site_ID: 1,
+ tags: {}
+};
+
+export const dailyPostSitePost = {
+ site_ID: dailyPostSiteId,
+ type: 'post'
+};
+
+export const dailyPromptPost = {
+ site_ID: dailyPostSiteId,
+ tags: {
+ 'daily prompts': {
+ slug: 'daily-prompts-2',
+ },
+ },
+ type: 'dp_prompt',
+ title: 'Crisis',
+ URL: 'https://dailypost.wordpress.com/2016/07/27/crisis/',
+ short_url: 'http://wp.me/p23sd-12Mf'
+};
+
+export const photoChallengePost = {
+ site_ID: dailyPostSiteId,
+ type: 'dp_photo_challenge'
+};
+
+export const discoverChallengePost = {
+ site_ID: dailyPostSiteId,
+ type: 'dp_discover'
+};
+
+export const sites = [
+ { ID: 72386110, name: 'Calypso Project P2', slug: 'calypsop2.wordpress.com' },
+ { ID: 108516984, name: 'Join the Narwhal Club', slug: 'jointhnarwhal.club' },
+ { ID: 6200060, name: '"I expected:"', slug: 'iexpected' }
+];
@@ -0,0 +1,36 @@
+/**
+ * External Dependencies
+ */
+import { assert } from 'chai';
+
+/**
+ * Internal Dependencies
+ */
+import * as posts from './fixtures';
+import * as helper from '../helper';
+
+describe( 'daily post helper', () => {
+ describe( 'isDailyPostChallengeOrPrompt', () => {
+ it( 'returns false if the post is not from daily post', () => {
+ assert.isFalse( helper.isDailyPostChallengeOrPrompt( posts.basicPost ) );
+ } );
+
+ it( 'returns false if the post is from daily post but is not a challenge or prompt', () => {
+ assert.isFalse( helper.isDailyPostChallengeOrPrompt( posts.dailyPostSitePost ) );
+ } );
+ } );
+
+ describe( 'getDailyPostType', () => {
+ it( 'returns "prompt" if the post is a daily prompt', () => {
+ assert.equal( 'prompt', helper.getDailyPostType( posts.dailyPromptPost ) );
+ } );
+
+ it( 'returns "photo" if the post is a photo challenge', () => {
+ assert.equal( 'photo', helper.getDailyPostType( posts.photoChallengePost ) );
+ } );
+
+ it( 'returns "discover" if the post is a discover challenge', () => {
+ assert.equal( 'discover', helper.getDailyPostType( posts.discoverChallengePost ) );
+ } );
+ } );
+} );
Oops, something went wrong.

0 comments on commit c4f8008

Please sign in to comment.