From 879929ffc47428081e7359694a13541ce61e6cc3 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Tue, 19 Jun 2018 21:40:52 +1000 Subject: [PATCH] Add Show Tips toggle (#7163) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Show Tips toggle Let the user re-enable tips via a Show Tips toggle in the More menu. * Typo: sholud → should --- .../header/fixed-toolbar-toggle/index.js | 24 +++++------ .../components/header/more-menu/index.js | 9 ++++- .../components/header/tips-toggle/index.js | 40 +++++++++++++++++++ nux/README.md | 29 +++++++++----- nux/components/dot-tip/index.js | 11 +++-- .../dot-tip/test/__snapshots__/index.js.snap | 2 +- nux/components/dot-tip/test/index.js | 10 ++--- nux/store/actions.js | 11 +++++ nux/store/reducer.js | 12 ++++-- nux/store/selectors.js | 13 +++++- nux/store/test/actions.js | 10 ++++- nux/store/test/reducer.js | 27 ++++++++++--- nux/store/test/selectors.js | 34 +++++++++++++--- 13 files changed, 181 insertions(+), 51 deletions(-) create mode 100644 edit-post/components/header/tips-toggle/index.js diff --git a/edit-post/components/header/fixed-toolbar-toggle/index.js b/edit-post/components/header/fixed-toolbar-toggle/index.js index 5561dc7eb99d82..e20ee631c0b65b 100644 --- a/edit-post/components/header/fixed-toolbar-toggle/index.js +++ b/edit-post/components/header/fixed-toolbar-toggle/index.js @@ -8,23 +8,18 @@ import { withSelect, withDispatch } from '@wordpress/data'; */ import { __ } from '@wordpress/i18n'; import { compose } from '@wordpress/element'; -import { MenuGroup, MenuItem, withInstanceId } from '@wordpress/components'; +import { MenuItem } from '@wordpress/components'; import { ifViewportMatches } from '@wordpress/viewport'; -function FeatureToggle( { onToggle, isActive } ) { +function FixedToolbarToggle( { onToggle, isActive } ) { return ( - - - { __( 'Fix Toolbar to Top' ) } - - + { __( 'Fix Toolbar to Top' ) } + ); } @@ -39,5 +34,4 @@ export default compose( [ }, } ) ), ifViewportMatches( 'medium' ), - withInstanceId, -] )( FeatureToggle ); +] )( FixedToolbarToggle ); diff --git a/edit-post/components/header/more-menu/index.js b/edit-post/components/header/more-menu/index.js index d880252e977c15..4799004916f731 100644 --- a/edit-post/components/header/more-menu/index.js +++ b/edit-post/components/header/more-menu/index.js @@ -11,6 +11,7 @@ import './style.scss'; import ModeSwitcher from '../mode-switcher'; import FixedToolbarToggle from '../fixed-toolbar-toggle'; import PluginMoreMenuGroup from '../plugins-more-menu-group'; +import TipsToggle from '../tips-toggle'; const MoreMenu = () => ( ( renderContent={ ( { onClose } ) => (
- + + + + + { __( 'Show Tips' ) } + + ); +} + +export default compose( [ + withSelect( ( select ) => ( { + isActive: select( 'core/nux' ).areTipsEnabled(), + } ) ), + withDispatch( ( dispatch, ownProps ) => ( { + onToggle() { + const { disableTips, enableTips } = dispatch( 'core/nux' ); + if ( ownProps.isActive ) { + disableTips(); + } else { + enableTips(); + } + ownProps.onToggle(); + }, + } ) ), +] )( TipsToggle ); diff --git a/nux/README.md b/nux/README.md index d3c9f069a9f886..ecb389f7095cf4 100644 --- a/nux/README.md +++ b/nux/README.md @@ -42,24 +42,33 @@ console.log( isVisible ); // true or false ``` -## Manually disabling tips +## Disabling and enabling tips -`disableTips` is a dispatch method that allows you to programmatically disable all tips. +Tips can be programatically disabled or enabled using the `disableTips` and `enableTips` dispatch methods. You can query the current setting by using the `areTipsEnabled` select method. + +Calling `enableTips` will also un-dismiss all previously dismissed tips. ```jsx - +const areTipsEnabled = select( 'core/nux' ).areTipsEnabled(); +return ( + +); ``` ## Triggering a guide diff --git a/nux/components/dot-tip/index.js b/nux/components/dot-tip/index.js index cba257d4af36d5..dff00729041641 100644 --- a/nux/components/dot-tip/index.js +++ b/nux/components/dot-tip/index.js @@ -38,7 +38,7 @@ export class DotTip extends Component { } render() { - const { children, isVisible, hasNextTip, onDismiss } = this.props; + const { children, isVisible, hasNextTip, onDismiss, onDisable } = this.props; if ( ! isVisible ) { return null; @@ -65,8 +65,8 @@ export class DotTip extends Component { ); @@ -83,11 +83,14 @@ export default compose( }; } ), withDispatch( ( dispatch, { id } ) => { - const { dismissTip } = dispatch( 'core/nux' ); + const { dismissTip, disableTips } = dispatch( 'core/nux' ); return { onDismiss() { dismissTip( id ); }, + onDisable() { + disableTips(); + }, }; } ), )( DotTip ); diff --git a/nux/components/dot-tip/test/__snapshots__/index.js.snap b/nux/components/dot-tip/test/__snapshots__/index.js.snap index a3a6773f5261fe..94a5c67a885a62 100644 --- a/nux/components/dot-tip/test/__snapshots__/index.js.snap +++ b/nux/components/dot-tip/test/__snapshots__/index.js.snap @@ -23,7 +23,7 @@ exports[`DotTip should render correctly 1`] = ` `; diff --git a/nux/components/dot-tip/test/index.js b/nux/components/dot-tip/test/index.js index 2f8bf4af2948a0..a2c324bf04a212 100644 --- a/nux/components/dot-tip/test/index.js +++ b/nux/components/dot-tip/test/index.js @@ -38,14 +38,14 @@ describe( 'DotTip', () => { expect( onDismiss ).toHaveBeenCalled(); } ); - it( 'should call onDismiss when the X button is clicked', () => { - const onDismiss = jest.fn(); + it( 'should call onDisable when the X button is clicked', () => { + const onDisable = jest.fn(); const wrapper = shallow( - + It looks like you’re writing a letter. Would you like help? ); - wrapper.find( 'IconButton[label="Dismiss tip"]' ).first().simulate( 'click' ); - expect( onDismiss ).toHaveBeenCalled(); + wrapper.find( 'IconButton[label="Disable tips"]' ).first().simulate( 'click' ); + expect( onDisable ).toHaveBeenCalled(); } ); } ); diff --git a/nux/store/actions.js b/nux/store/actions.js index 95b14731ab06e0..ad8adb79c5530d 100644 --- a/nux/store/actions.js +++ b/nux/store/actions.js @@ -39,3 +39,14 @@ export function disableTips() { type: 'DISABLE_TIPS', }; } + +/** + * Returns an action object that, when dispatched, makes all tips show again. + * + * @return {Object} Action object. + */ +export function enableTips() { + return { + type: 'ENABLE_TIPS', + }; +} diff --git a/nux/store/reducer.js b/nux/store/reducer.js index e8ba1abb7b0a5a..5ebf8ea394e70b 100644 --- a/nux/store/reducer.js +++ b/nux/store/reducer.js @@ -25,16 +25,19 @@ export function guides( state = [], action ) { } /** - * Reducer that tracks whether or not tips are globally disabled. + * Reducer that tracks whether or not tips are globally enabled. * * @param {boolean} state Current state. * @param {Object} action Dispatched action. * * @return {boolean} Updated state. */ -export function areTipsDisabled( state = false, action ) { +export function areTipsEnabled( state = true, action ) { switch ( action.type ) { case 'DISABLE_TIPS': + return false; + + case 'ENABLE_TIPS': return true; } @@ -57,11 +60,14 @@ export function dismissedTips( state = {}, action ) { ...state, [ action.id ]: true, }; + + case 'ENABLE_TIPS': + return {}; } return state; } -const preferences = combineReducers( { areTipsDisabled, dismissedTips } ); +const preferences = combineReducers( { areTipsEnabled, dismissedTips } ); export default combineReducers( { guides, preferences } ); diff --git a/nux/store/selectors.js b/nux/store/selectors.js index bf7365df9f27f2..61f0193d90f46c 100644 --- a/nux/store/selectors.js +++ b/nux/store/selectors.js @@ -51,7 +51,7 @@ export const getAssociatedGuide = createSelector( * @return {boolean} Whether or not the given tip is showing. */ export function isTipVisible( state, id ) { - if ( state.preferences.areTipsDisabled ) { + if ( ! state.preferences.areTipsEnabled ) { return false; } @@ -66,3 +66,14 @@ export function isTipVisible( state, id ) { return true; } + +/** + * Returns whether or not tips are globally enabled. + * + * @param {Object} state Global application state. + * + * @return {boolean} Whether tips are globally enabled. + */ +export function areTipsEnabled( state ) { + return state.preferences.areTipsEnabled; +} diff --git a/nux/store/test/actions.js b/nux/store/test/actions.js index 1aa4d0cf6f2e34..4e22afe03c8b82 100644 --- a/nux/store/test/actions.js +++ b/nux/store/test/actions.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import { triggerGuide, dismissTip, disableTips } from '../actions'; +import { triggerGuide, dismissTip, disableTips, enableTips } from '../actions'; describe( 'actions', () => { describe( 'triggerGuide', () => { @@ -29,4 +29,12 @@ describe( 'actions', () => { } ); } ); } ); + + describe( 'enableTips', () => { + it( 'should return an ENABLE_TIPS action', () => { + expect( enableTips() ).toEqual( { + type: 'ENABLE_TIPS', + } ); + } ); + } ); } ); diff --git a/nux/store/test/reducer.js b/nux/store/test/reducer.js index a40fabdf49f84f..d2982a87d70501 100644 --- a/nux/store/test/reducer.js +++ b/nux/store/test/reducer.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import { guides, areTipsDisabled, dismissedTips } from '../reducer'; +import { guides, areTipsEnabled, dismissedTips } from '../reducer'; describe( 'reducer', () => { describe( 'guides', () => { @@ -20,15 +20,22 @@ describe( 'reducer', () => { } ); } ); - describe( 'areTipsDisabled', () => { - it( 'should default to false', () => { - expect( areTipsDisabled( undefined, {} ) ).toBe( false ); + describe( 'areTipsEnabled', () => { + it( 'should default to true', () => { + expect( areTipsEnabled( undefined, {} ) ).toBe( true ); } ); it( 'should flip when tips are disabled', () => { - const state = areTipsDisabled( false, { + const state = areTipsEnabled( true, { type: 'DISABLE_TIPS', } ); + expect( state ).toBe( false ); + } ); + + it( 'should flip when tips are enabled', () => { + const state = areTipsEnabled( false, { + type: 'ENABLE_TIPS', + } ); expect( state ).toBe( true ); } ); } ); @@ -47,5 +54,15 @@ describe( 'reducer', () => { 'test/tip': true, } ); } ); + + it( 'should reset if tips are enabled', () => { + const initialState = { + 'test/tip': true, + }; + const state = dismissedTips( initialState, { + type: 'ENABLE_TIPS', + } ); + expect( state ).toEqual( {} ); + } ); } ); } ); diff --git a/nux/store/test/selectors.js b/nux/store/test/selectors.js index 08f6c7eea38f66..ed63a7fa828de5 100644 --- a/nux/store/test/selectors.js +++ b/nux/store/test/selectors.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import { getAssociatedGuide, isTipVisible } from '../selectors'; +import { getAssociatedGuide, isTipVisible, areTipsEnabled } from '../selectors'; describe( 'selectors', () => { describe( 'getAssociatedGuide', () => { @@ -57,7 +57,7 @@ describe( 'selectors', () => { const state = { guides: [], preferences: { - areTipsDisabled: false, + areTipsEnabled: true, dismissedTips: {}, }, }; @@ -68,7 +68,7 @@ describe( 'selectors', () => { const state = { guides: [], preferences: { - areTipsDisabled: true, + areTipsEnabled: false, dismissedTips: {}, }, }; @@ -79,7 +79,7 @@ describe( 'selectors', () => { const state = { guides: [], preferences: { - areTipsDisabled: false, + areTipsEnabled: true, dismissedTips: { 'test/tip': true, }, @@ -94,11 +94,35 @@ describe( 'selectors', () => { [ 'test/tip-1', 'test/tip-2', 'test/tip-3' ], ], preferences: { - areTipsDisabled: false, + areTipsEnabled: true, dismissedTips: {}, }, }; expect( isTipVisible( state, 'test/tip-2' ) ).toBe( false ); } ); } ); + + describe( 'areTipsEnabled', () => { + it( 'should return true if tips are enabled', () => { + const state = { + guides: [], + preferences: { + areTipsEnabled: true, + dismissedTips: {}, + }, + }; + expect( areTipsEnabled( state ) ).toBe( true ); + } ); + + it( 'should return false if tips are disabled', () => { + const state = { + guides: [], + preferences: { + areTipsEnabled: false, + dismissedTips: {}, + }, + }; + expect( areTipsEnabled( state ) ).toBe( false ); + } ); + } ); } );