From acf9a1adf1e568bdcbe37c71b574711403478ea0 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Fri, 10 Aug 2018 10:28:39 -0400 Subject: [PATCH] Add and use Checklist components, remove blocks Adds Components from #26216 Uses components for WooCommerce Store checklist Uses components for ChecklistShow Removes blocks (discourage block usage) --- assets/stylesheets/_components.scss | 2 +- client/blocks/checklist/README.md | 83 -------- client/blocks/checklist/docs/example.jsx | 117 ----------- client/blocks/checklist/index.jsx | 113 ---------- client/components/checklist/README.md | 90 ++++++++ client/components/checklist/docs/example.jsx | 68 ++++++ .../checklist/header.js} | 11 +- client/components/checklist/index.js | 72 +++++++ .../checklist/style.scss | 16 ++ .../checklist/task-placeholder.js} | 6 +- .../checklist/task.js} | 90 ++++---- client/devdocs/design/blocks.jsx | 2 - client/devdocs/design/component-examples.js | 2 +- client/devdocs/design/index.jsx | 2 + client/devdocs/design/playground-scope.js | 3 +- .../woocommerce/app/dashboard/setup/tasks.js | 193 +++++++++--------- .../checklist/checklist-show/index.jsx | 52 +++-- 17 files changed, 433 insertions(+), 489 deletions(-) delete mode 100644 client/blocks/checklist/README.md delete mode 100644 client/blocks/checklist/docs/example.jsx delete mode 100644 client/blocks/checklist/index.jsx create mode 100644 client/components/checklist/README.md create mode 100644 client/components/checklist/docs/example.jsx rename client/{blocks/checklist/checklist-header.jsx => components/checklist/header.js} (95%) create mode 100644 client/components/checklist/index.js rename client/{blocks => components}/checklist/style.scss (96%) rename client/{blocks/checklist/checklist-placeholder.jsx => components/checklist/task-placeholder.js} (89%) rename client/{blocks/checklist/checklist-task.jsx => components/checklist/task.js} (60%) diff --git a/assets/stylesheets/_components.scss b/assets/stylesheets/_components.scss index d0ec8fa5685fa..939121ae861c0 100644 --- a/assets/stylesheets/_components.scss +++ b/assets/stylesheets/_components.scss @@ -103,7 +103,7 @@ @import 'components/card/style'; @import 'components/card-heading/style'; @import 'components/chart/style'; -@import 'blocks/checklist/style'; +@import 'components/checklist/style'; @import 'components/clipboard-button-input/style'; @import 'components/domains/contact-details-form-fields/style'; @import 'components/community-translator/style'; diff --git a/client/blocks/checklist/README.md b/client/blocks/checklist/README.md deleted file mode 100644 index 184abcc701a5c..0000000000000 --- a/client/blocks/checklist/README.md +++ /dev/null @@ -1,83 +0,0 @@ -Checklist -=========== - -Checklist of `ChecklistItem`s. - -#### How to use: - -```jsx -import Checklist from 'components/checklist'; - -export default class ChecklistExample extends Component { - static displayName = 'Checklist'; - - state = { - showPlaceholder: false, - tasks: [ - { - id: 'first-completed-task', - title: 'A completed task', - completedTitle: 'You completed the first task', - completedButtonText: 'View', - description: 'This row shows how completed tasks look.', - duration: '2 mins', - url: 'https://wordpress.com/url-to-the-first-task', - completed: true, - }, - { - id: 'second-completed-task', - title: 'A second completed task', - completedTitle: 'You completed the second task', - description: 'This row shows how completed tasks look.', - duration: '2 mins', - url: 'https://wordpress.com/url-to-the-second-task', - completed: true, - }, - { - id: 'site-name', - title: "Add your site's name or logo", - completedTitle: "You chose your site's name", - completedButtonText: 'Change', - description: "A logo or site name helps people know what site they're looking at.", - duration: '3 mins', - url: 'https://wordpress.com/url-to-site-name', - completed: false, - }, - ], - }; - - handleAction = id => { - const theTask = find( this.state.tasks, { id } ); - console.log( `You will move to ${ theTask.url }.` ); - }; - - handleToggle = id => { - const theTask = find( this.state.tasks, { id } ); - theTask.completed = ! theTask.completed; - - this.setState( { tasks: [ ...this.state.tasks ] } ); - }; - - render() { - return ( -
- -
- ); - } -} -``` - -#### Props - -* `tasks`: (array) A set of task objects, passed to `ChecklistItem`s -* `onAction`: (function) Points the user to the given item's action URL. Takes the item's `id`. -* `onToggle`: (function) Changes the state of the given item, toggled on or off. Takes the item's `id`. -* `isLoading`: (boolean) Whether to show the placeholder or not. -* `placeholderCount`: (number) The number of placeholder items to show. diff --git a/client/blocks/checklist/docs/example.jsx b/client/blocks/checklist/docs/example.jsx deleted file mode 100644 index 50fc7908f9de4..0000000000000 --- a/client/blocks/checklist/docs/example.jsx +++ /dev/null @@ -1,117 +0,0 @@ -/** - * External dependencies - * - * @format - */ - -import React, { Component } from 'react'; -import { find } from 'lodash'; - -/** - * Internal dependencies - */ -import Button from 'components/button'; -import Checklist from '../'; - -export default class ChecklistExample extends Component { - static displayName = 'Checklist'; - - state = { - showPlaceholder: false, - tasks: [ - { - id: 'first-completed-task', - title: 'A completed task', - completedTitle: 'You completed the first task', - completedButtonText: 'View', - description: 'This row shows how completed tasks look.', - duration: '2 mins', - url: 'https://wordpress.com/url-to-the-first-task', - completed: true, - }, - { - id: 'second-completed-task', - title: 'A second completed task', - completedTitle: 'You completed the second task', - description: 'This row shows how completed tasks look.', - duration: '2 mins', - url: 'https://wordpress.com/url-to-the-second-task', - completed: true, - }, - { - id: 'site-name', - title: "Add your site's name or logo", - completedTitle: "You chose your site's name", - completedButtonText: 'Change', - description: "A logo or site name helps people know what site they're looking at.", - duration: '3 mins', - url: 'https://wordpress.com/url-to-site-name', - completed: false, - }, - { - id: 'site-colors', - title: "Pick your site's colors", - completedTitle: "You picked your site's colors", - completedButtonText: 'Change', - description: 'Add your personal touch to your site by picking your colors.', - duration: '2 mins', - url: 'https://wordpress.com/url-to-site-colors', - completed: false, - }, - { - id: 'site-fonts', - title: "Pick your site's fonts", - completedTitle: "You picked your site's fonts", - description: 'Add your personal touch to your site by picking your fonts.', - duration: '2 mins', - url: 'https://wordpress.com/url-to-site-fonts', - completed: false, - }, - { - id: 'header-image', - title: 'Change your header image', - completedTitle: 'You changed your header image', - description: 'Personalize your site with a custom image or background color.', - duration: '2 mins', - url: 'https://wordpress.com/url-to-header-image', - completed: false, - }, - ], - }; - - togglePlaceholder = () => { - this.setState( { showPlaceholder: ! this.state.showPlaceholder } ); - }; - - handleAction = id => { - const theTask = find( this.state.tasks, { id } ); - console.log( `You will move to ${ theTask.url }.` ); - }; - - handleToggle = id => { - const theTask = find( this.state.tasks, { id } ); - theTask.completed = ! theTask.completed; - - this.setState( { tasks: [ ...this.state.tasks ] } ); - }; - - render() { - const toggleText = this.state.showPlaceholder ? 'Hide Placeholder' : 'Show Placeholder'; - - return ( -
- -
- -
- ); - } -} diff --git a/client/blocks/checklist/index.jsx b/client/blocks/checklist/index.jsx deleted file mode 100644 index 461b9aa084c5e..0000000000000 --- a/client/blocks/checklist/index.jsx +++ /dev/null @@ -1,113 +0,0 @@ -/** - * External dependencies - * - * @format - */ - -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; -import { filter, noop, times } from 'lodash'; -import classNames from 'classnames'; - -/** - * Internal dependencies - */ -import ChecklistHeader from './checklist-header'; -import ChecklistTask from './checklist-task'; -import ChecklistPlaceholder from './checklist-placeholder'; -import { loadTrackingTool } from 'state/analytics/actions'; - -export class Checklist extends Component { - static propTypes = { - tasks: PropTypes.array, - onAction: PropTypes.func, - onToggle: PropTypes.func, - isLoading: PropTypes.bool, - placeholderCount: PropTypes.number, - }; - - static defaultProps = { - tasks: [], - onAction: noop, - onToggle: noop, - isLoading: true, - placeholderCount: 5, - }; - - state = { - hideCompleted: false, - }; - - componentDidMount() { - this.props.loadTrackingTool( 'HotJar' ); - } - - toggleCompleted = () => { - this.setState( { hideCompleted: ! this.state.hideCompleted } ); - }; - - getCompletedTasks() { - return filter( this.props.tasks, task => task.completed ); - } - - getUncompletedTasks() { - return filter( this.props.tasks, task => ! task.completed ); - } - - renderPlaceholder() { - return ( -
- - { times( this.props.placeholderCount, index => ( - - ) ) } -
- ); - } - - renderTask = task => { - return ( - - ); - }; - - render() { - const { isLoading, tasks } = this.props; - - if ( isLoading ) { - return this.renderPlaceholder(); - } - - return ( -
- - { ! this.state.hideCompleted && this.getCompletedTasks().map( this.renderTask ) } - { this.getUncompletedTasks().map( this.renderTask ) } -
- ); - } -} - -export default connect( - null, - { loadTrackingTool } -)( Checklist ); diff --git a/client/components/checklist/README.md b/client/components/checklist/README.md new file mode 100644 index 0000000000000..8a84197b89a2c --- /dev/null +++ b/client/components/checklist/README.md @@ -0,0 +1,90 @@ +Checklist +======= + +`Checklist` and `Task` are components used to render checklists. + +If your checklist tasks use checklist state from Redux, you can use `Task` from `blocks/checklist/tasks` to pull state by the `id` prop. + +## `Checklist` props + +### `isPlaceholder { bool } - default: false` + +Render as a placeholder. + +### `inferCompletedCount { bool } - default: false` + +If `Task` children will have a provided `complete` prop, the `Checklist` will count the completed +tasks. This will not work when using connected tasks (see `blocks/checklist/task`). + +### `completedCount { number }` + +If you cannot use `inferCompletedCount` (you're using connected `Task`s), provide the completion +count here. + +## `Task` props + +### `completed { bool }` + +Whether the task is complete. + +### `onClick { Function }` + +Handle the action button click. + +### `onDismiss { func }` + +Handle dismissal (or un-dismissal) click. + +### `buttonPrimary { bool }` + +Display the action button as primary. + +### `completedButtonText { node }` + +Button text on complete. + +### `completedTitle { node }` + +Override title when completed (fallback to `title` prop) + +### `description { node }` + +Description + +### `duration { string }` + +Duration, like "2 minutes". + +Translate as `translate( '%d minutes', '%d minutes', { count: 2, args: [ 2 ] } )`. + +### `title { node }` + +Task title + +## Usage + +```jsx + + + + +``` diff --git a/client/components/checklist/docs/example.jsx b/client/components/checklist/docs/example.jsx new file mode 100644 index 0000000000000..cff4b90c36c58 --- /dev/null +++ b/client/components/checklist/docs/example.jsx @@ -0,0 +1,68 @@ +/** @format */ +/** + * External dependencies + */ +import React, { PureComponent } from 'react'; + +/** + * Internal dependencies + */ +import accept from 'lib/accept'; +import Button from 'components/button'; +import Checklist from '../'; +import Task from '../task'; + +export default class ChecklistExample extends PureComponent { + static displayName = 'ChecklistExample'; + + state = { + showPlaceholder: false, + }; + + togglePlaceholder = () => + void this.setState( ( { showPlaceholder } ) => ( { showPlaceholder: ! showPlaceholder } ) ); + + getClickHandler = taskId => () => + accept( + 'Will you complete this thing?', + accepted => ( accepted ? void this.setState( { [ taskId ]: true } ) : undefined ), + 'Yes', + 'No' + ); + getToggleHandler = taskId => () => + void this.setState( state => ( { [ taskId ]: ! state[ taskId ] } ) ); + + render() { + return ( + <> + + + + + + + ); + } +} diff --git a/client/blocks/checklist/checklist-header.jsx b/client/components/checklist/header.js similarity index 95% rename from client/blocks/checklist/checklist-header.jsx rename to client/components/checklist/header.js index f35ec064a14fd..ad16c404dbf38 100644 --- a/client/blocks/checklist/checklist-header.jsx +++ b/client/components/checklist/header.js @@ -1,20 +1,18 @@ +/** @format */ /** * External dependencies - * - * @format */ - -import React, { PureComponent } from 'react'; +import Gridicon from 'gridicons'; import PropTypes from 'prop-types'; +import React, { PureComponent } from 'react'; import { localize } from 'i18n-calypso'; -import Gridicon from 'gridicons'; /** * Internal dependencies */ import Card from 'components/card'; -import ScreenReaderText from 'components/screen-reader-text'; import ProgressBar from 'components/progress-bar'; +import ScreenReaderText from 'components/screen-reader-text'; export class ChecklistHeader extends PureComponent { static propTypes = { @@ -40,6 +38,7 @@ export class ChecklistHeader extends PureComponent {
+ { /* eslint-disable-next-line jsx-a11y/label-has-for */ } diff --git a/client/components/checklist/index.js b/client/components/checklist/index.js new file mode 100644 index 0000000000000..7c82e3438b7ef --- /dev/null +++ b/client/components/checklist/index.js @@ -0,0 +1,72 @@ +/** @format */ +/** + * External dependencies + */ +import classNames from 'classnames'; +import React, { Children, PureComponent } from 'react'; +import PropTypes from 'prop-types'; +import { times } from 'lodash'; + +/** + * Internal dependencies + */ +import ChecklistHeader from 'components/checklist/header'; +import TaskPlaceholder from 'components/checklist/task-placeholder'; + +export default class Checklist extends PureComponent { + static propTyps = { + completedCount: PropTypes.number, + inferCompletedCount: PropTypes.bool, + isPlaceholder: PropTypes.bool, + }; + + state = { hideCompleted: false }; + + toggleCompleted = () => + this.setState( ( { hideCompleted } ) => ( { hideCompleted: ! hideCompleted } ) ); + + renderPlaceholder() { + return ( +
+ +
+ { times( Children.count( this.props.children ), index => ( + + ) ) } +
+
+ ); + } + + render() { + if ( this.props.isPlaceholder ) { + return this.renderPlaceholder(); + } + + const { children, completedCount, inferCompletedCount } = this.props; + + const count = inferCompletedCount + ? Children.map( children, child => child.props.completed ).reduce( + ( acc, completed ) => ( true === completed ? acc + 1 : acc ), + 0 + ) + : completedCount; + + return ( +
+ +
{ children }
+
+ ); + } +} diff --git a/client/blocks/checklist/style.scss b/client/components/checklist/style.scss similarity index 96% rename from client/blocks/checklist/style.scss rename to client/components/checklist/style.scss index 36e804a8d922e..bf31a8d856c7c 100644 --- a/client/blocks/checklist/style.scss +++ b/client/components/checklist/style.scss @@ -86,7 +86,23 @@ } } +.checklist__tasks { + display: flex; + flex-direction: column; +} + .checklist__task { + width: 100%; + order: 100; + + .hide-completed &.is-completed { + display: none; + } + + &.is-completed { + order: 0; + } + &.card { display: flex; flex-direction: row; diff --git a/client/blocks/checklist/checklist-placeholder.jsx b/client/components/checklist/task-placeholder.js similarity index 89% rename from client/blocks/checklist/checklist-placeholder.jsx rename to client/components/checklist/task-placeholder.js index 08d9e91591b85..aabdb8497e201 100644 --- a/client/blocks/checklist/checklist-placeholder.jsx +++ b/client/components/checklist/task-placeholder.js @@ -1,9 +1,7 @@ +/** @format */ /** * External dependencies - * - * @format */ - import React from 'react'; /** @@ -11,7 +9,7 @@ import React from 'react'; */ import Card from 'components/card'; -export default function ChecklistPlaceholder() { +export default function TaskPlaceholder() { return (
diff --git a/client/blocks/checklist/checklist-task.jsx b/client/components/checklist/task.js similarity index 60% rename from client/blocks/checklist/checklist-task.jsx rename to client/components/checklist/task.js index 9517f6dd78405..58f6db74d7f49 100644 --- a/client/blocks/checklist/checklist-task.jsx +++ b/client/components/checklist/task.js @@ -1,68 +1,56 @@ +/** @format */ /** * External dependencies - * - * @format */ - -import React, { PureComponent } from 'react'; -import PropTypes from 'prop-types'; -import { localize } from 'i18n-calypso'; -import { noop } from 'lodash'; import classNames from 'classnames'; import Gridicon from 'gridicons'; +import PropTypes from 'prop-types'; +import React, { PureComponent } from 'react'; +import { localize } from 'i18n-calypso'; /** * Internal dependencies */ import Button from 'components/button'; -import Card from 'components/card'; +import CompactCard from 'components/card/compact'; import Focusable from 'components/focusable'; import ScreenReaderText from 'components/screen-reader-text'; -export class ChecklistTask extends PureComponent { +export class Task extends PureComponent { static propTypes = { - id: PropTypes.string.isRequired, - title: PropTypes.string.isRequired, - buttonText: PropTypes.string, - buttonPrimary: PropTypes.bool, - completedTitle: PropTypes.string, - completedButtonText: PropTypes.string, - description: PropTypes.string.isRequired, - duration: PropTypes.string, completed: PropTypes.bool, - onAction: PropTypes.func, - onToggle: PropTypes.func, - }; + onClick: PropTypes.func, + onDismiss: PropTypes.func, - static defaultProps = { - onClick: noop, - }; - - handleClick = () => { - this.props.onAction( this.props.id ); - }; - - handleToggle = () => { - this.props.onToggle( this.props.id ); + buttonPrimary: PropTypes.bool, + completedButtonText: PropTypes.node, + completedTitle: PropTypes.node, + description: PropTypes.node, + duration: PropTypes.string, + title: PropTypes.node.isRequired, + translate: PropTypes.func.isRequired, }; render() { const { buttonPrimary, completed, - completedTitle, completedButtonText, + completedTitle, description, duration, + onClick, + onDismiss, title, translate, } = this.props; const { buttonText = translate( 'Do it!' ) } = this.props; const hasActionlink = completed && completedButtonText; + const ToggleContainer = onDismiss ? Focusable : 'div'; + return ( -

-

@@ -82,11 +70,7 @@ export class ChecklistTask extends PureComponent { ) }
- { duration && ( @@ -95,19 +79,31 @@ export class ChecklistTask extends PureComponent { ) }
- - { completed ? translate( 'Mark as uncompleted' ) : translate( 'Mark as completed' ) } + { /* eslint-disable no-nested-ternary */ + onDismiss + ? completed + ? translate( 'Mark as uncompleted' ) + : translate( 'Mark as completed' ) + : completed + ? translate( 'Complete' ) + : translate( 'Not complete' ) + /* eslint-enable no-nested-ternary */ + } - { } - -
+ + + ); } } -export default localize( ChecklistTask ); +export default localize( Task ); diff --git a/client/devdocs/design/blocks.jsx b/client/devdocs/design/blocks.jsx index 2ab0242e3149f..b18fb93408fd2 100644 --- a/client/devdocs/design/blocks.jsx +++ b/client/devdocs/design/blocks.jsx @@ -26,7 +26,6 @@ import AllSites from 'blocks/all-sites/docs/example'; import CreditCardForm from 'blocks/credit-card-form/docs/example'; import CalendarButton from 'blocks/calendar-button/docs/example'; import CalendarPopover from 'blocks/calendar-popover/docs/example'; -import Checklist from 'blocks/checklist/docs/example'; import AuthorSelector from 'blocks/author-selector/docs/example'; import CommentButtons from 'blocks/comment-button/docs/example'; import DisconnectJetpackDialog from 'blocks/disconnect-jetpack/docs/example'; @@ -135,7 +134,6 @@ export default class AppComponents extends React.Component { - diff --git a/client/devdocs/design/component-examples.js b/client/devdocs/design/component-examples.js index e85faf8f192af..97dc7db3bf7b6 100644 --- a/client/devdocs/design/component-examples.js +++ b/client/devdocs/design/component-examples.js @@ -14,7 +14,7 @@ export Buttons from 'components/button/docs/example'; export Cards from 'components/card/docs/example'; export CardHeading from 'components/card-heading/docs/example'; export Chart from 'components/chart/docs/example'; -export Checklist from 'blocks/checklist/docs/example'; +export Checklist from 'components/checklist/docs/example'; export ClipboardButtonInput from 'components/clipboard-button-input/docs/example'; export ClipboardButtons from 'components/forms/clipboard-button/docs/example'; export Collection from 'devdocs/design/search-collection'; diff --git a/client/devdocs/design/index.jsx b/client/devdocs/design/index.jsx index 7580000b2a701..867cc89a8e4eb 100644 --- a/client/devdocs/design/index.jsx +++ b/client/devdocs/design/index.jsx @@ -39,6 +39,7 @@ import Buttons from 'components/button/docs/example'; import CardHeading from 'components/card-heading/docs/example'; import Cards from 'components/card/docs/example'; import Chart from 'components/chart/docs/example'; +import Checklist from 'components/checklist/docs/example'; import ClipboardButtonInput from 'components/clipboard-button-input/docs/example'; import ClipboardButtons from 'components/forms/clipboard-button/docs/example'; import Collection from 'devdocs/design/search-collection'; @@ -183,6 +184,7 @@ class DesignAssets extends React.Component { + diff --git a/client/devdocs/design/playground-scope.js b/client/devdocs/design/playground-scope.js index 60d955acbf137..f259c2fa87727 100644 --- a/client/devdocs/design/playground-scope.js +++ b/client/devdocs/design/playground-scope.js @@ -20,7 +20,8 @@ export ButtonGroup from 'components/button-group'; export Button from 'components/button'; export Card from 'components/card'; export CardHeading from 'components/card-heading'; -export Checklist from 'blocks/checklist'; +export Checklist from 'components/checklist'; +export ChecklistTask from 'components/checklist/task'; export ClipboardButtonInput from 'components/clipboard-button-input'; export ClipboardButton from 'components/forms/clipboard-button'; export Collection from 'devdocs/design/search-collection'; diff --git a/client/extensions/woocommerce/app/dashboard/setup/tasks.js b/client/extensions/woocommerce/app/dashboard/setup/tasks.js index 5174d6105f2fa..0aa8f46716193 100644 --- a/client/extensions/woocommerce/app/dashboard/setup/tasks.js +++ b/client/extensions/woocommerce/app/dashboard/setup/tasks.js @@ -9,7 +9,6 @@ import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { localize } from 'i18n-calypso'; -import { find } from 'lodash'; import page from 'page'; /** @@ -20,7 +19,8 @@ import { getTriedCustomizerDuringInitialSetup, getCheckedTaxSetup, } from 'woocommerce/state/sites/setup-choices/selectors'; -import Checklist from 'blocks/checklist'; +import Checklist from 'components/checklist'; +import Task from 'components/checklist/task'; import { getTotalProducts, areProductsLoaded } from 'woocommerce/state/sites/products/selectors'; import { fetchProducts } from 'woocommerce/state/sites/products/actions'; import { fetchPaymentMethods } from 'woocommerce/state/sites/payment-methods/actions'; @@ -30,6 +30,7 @@ import { arePaymentsSetup } from 'woocommerce/state/ui/payments/methods/selector import { getLink } from 'woocommerce/lib/nav-utils'; import { recordTrack } from 'woocommerce/lib/analytics'; import { areAnyShippingMethodsEnabled } from 'woocommerce/state/ui/shipping/zones/selectors'; +import { loadTrackingTool } from 'state/analytics/actions'; class SetupTasks extends Component { static propTypes = { @@ -49,6 +50,8 @@ class SetupTasks extends Component { this.props.fetchProducts( site.ID, { page: 1 } ); } } + + this.props.loadTrackingTool( 'HotJar' ); }; componentWillReceiveProps = newProps => { @@ -64,114 +67,113 @@ class SetupTasks extends Component { } }; - getSetupTasks = () => { - const { - site, - triedCustomizer, - hasProducts, - paymentsAreSetUp, - shippingIsSetUp, - taxesAreSetUp, - translate, - } = this.props; - const siteSlug = encodeURIComponent( '//' + site.slug ); - const customizerUrl = getLink( - 'https://:site/wp-admin/customize.php?store-wpcom-nux=true&return=' + siteSlug, - site - ); - - return [ - { - id: 'add-product', - title: translate( 'Add a product' ), - buttonText: translate( 'Add a product' ), - buttonPrimary: true, - completedTitle: translate( 'You have added a product' ), - completedButtonText: translate( 'View products' ), - description: translate( 'Start by adding the first product to your\u00a0store.' ), - duration: translate( '%d minute', '%d minutes', { count: 3, args: [ 3 ] } ), - url: getLink( '/store/product/:site', site ), - completed: hasProducts, - }, - { - id: 'set-up-shipping', - title: translate( 'Review shipping' ), - buttonText: translate( 'Review shipping' ), - buttonPrimary: true, - completedTitle: translate( 'Shipping is set up' ), - completedButtonText: translate( 'View shipping' ), - description: translate( "We've set up shipping based on your store location." ), - duration: translate( '%d minute', '%d minutes', { count: 2, args: [ 2 ] } ), - url: getLink( '/store/settings/shipping/:site', site ), - completed: shippingIsSetUp, - }, - { - id: 'set-up-payments', - title: translate( 'Review payments' ), - buttonText: translate( 'Review payments' ), - buttonPrimary: true, - completedTitle: translate( 'Payments are set up' ), - completedButtonText: translate( 'Review payments' ), - description: translate( 'Choose how you would like your customers to pay you.' ), - duration: translate( '%d minute', '%d minutes', { count: 2, args: [ 2 ] } ), - url: getLink( '/store/settings/payments/:site', site ), - completed: paymentsAreSetUp, - }, - { - id: 'set-up-taxes', - title: translate( 'Review taxes' ), - buttonText: translate( 'Review taxes' ), - buttonPrimary: true, - completedTitle: translate( 'Taxes are setup' ), - completedButtonText: translate( 'Review taxes' ), - description: translate( "We've set up automatic tax calculations for you." ), - duration: translate( '%d minute', '%d minutes', { count: 2, args: [ 2 ] } ), - url: getLink( '/store/settings/taxes/:site', site ), - completed: taxesAreSetUp, - }, - { - id: 'view-and-customize', - title: translate( 'View and customize' ), - buttonText: translate( 'Customize' ), - buttonPrimary: true, - completedTitle: translate( 'View and customize' ), - completedButtonText: translate( 'View and customize' ), - description: translate( - 'View your store and make any final tweaks before opening for business.' - ), - duration: translate( '%d minute', '%d minutes', { count: 4, args: [ 4 ] } ), - url: customizerUrl, - completed: triedCustomizer, - }, - ]; - }; - - handleAction = id => { - const task = find( this.getSetupTasks(), { id } ); - + getClickHandler = ( id, url ) => () => { recordTrack( 'calypso_woocommerce_dashboard_action_click', { action: id, } ); if ( 'view-and-customize' === id ) { this.props.setTriedCustomizerDuringInitialSetup( this.props.site.ID, true ); - window.open( task.url ); + window.open( url ); } else { - page.show( task.url ); + page.show( url ); } }; render = () => { + const { + site, + triedCustomizer, + hasProducts, + paymentsAreSetUp, + shippingIsSetUp, + taxesAreSetUp, + translate, + } = this.props; + const siteSlug = encodeURIComponent( '//' + site.slug ); return (
+ isPlaceholder={ this.props.loading || ! this.props.productsLoaded } + inferCompletedCount + > + + + + + +
); }; @@ -194,6 +196,7 @@ function mapDispatchToProps( dispatch ) { { fetchPaymentMethods, fetchProducts, + loadTrackingTool, setTriedCustomizerDuringInitialSetup, }, dispatch diff --git a/client/my-sites/checklist/checklist-show/index.jsx b/client/my-sites/checklist/checklist-show/index.jsx index 5b07ac4d5d6ce..7472b4f5561be 100644 --- a/client/my-sites/checklist/checklist-show/index.jsx +++ b/client/my-sites/checklist/checklist-show/index.jsx @@ -11,7 +11,8 @@ import { find, get } from 'lodash'; /** * Internal dependencies */ -import Checklist from 'blocks/checklist'; +import Checklist from 'components/checklist'; +import Task from 'components/checklist/task'; import { tasks as jetpackTasks } from '../jetpack-checklist'; import { requestSiteChecklistTaskUpdate } from 'state/checklist/actions'; import { getSelectedSiteId } from 'state/ui/selectors'; @@ -19,13 +20,16 @@ import getSiteChecklist from 'state/selectors/get-site-checklist'; import { isJetpackSite, getSiteSlug } from 'state/sites/selectors'; import QuerySiteChecklist from 'components/data/query-site-checklist'; import { launchTask, tasks as wpcomTasks } from '../onboardingChecklist'; -import { mergeObjectIntoArrayById } from '../util'; -import { recordTracksEvent } from 'state/analytics/actions'; +import { loadTrackingTool, recordTracksEvent } from 'state/analytics/actions'; import { createNotice } from 'state/notices/actions'; import { requestGuidedTour } from 'state/ui/guided-tours/actions'; class ChecklistShow extends PureComponent { - handleAction = id => { + componentDidMount() { + this.props.loadTrackingTool( 'HotJar' ); + } + + handleAction = id => () => { const { requestTour, siteSlug, tasks, track } = this.props; const task = find( tasks, { id } ); @@ -38,7 +42,7 @@ class ChecklistShow extends PureComponent { } ); }; - handleToggle = id => { + handleToggle = id => () => { const { notify, siteId, tasks, update } = this.props; const task = find( tasks, { id } ); @@ -49,17 +53,30 @@ class ChecklistShow extends PureComponent { }; render() { - const { siteId, tasks } = this.props; + const { isJetpack, siteId, taskStatuses } = this.props; + const tasks = isJetpack ? jetpackTasks : wpcomTasks; return ( { siteId && } - + + { tasks.map( task => ( + + ) ) } + ); } @@ -67,20 +84,17 @@ class ChecklistShow extends PureComponent { const mapStateToProps = state => { const siteId = getSelectedSiteId( state ); - const siteSlug = getSiteSlug( state, siteId ); - const siteChecklist = getSiteChecklist( state, siteId ); - const isJetpack = isJetpackSite( state, siteId ); - const tasks = isJetpack ? jetpackTasks : wpcomTasks; - const tasksFromServer = get( siteChecklist, [ 'tasks' ] ); return { + isJetpack: isJetpackSite( state, siteId ), siteId, - siteSlug, - tasks: tasksFromServer ? mergeObjectIntoArrayById( tasks, tasksFromServer ) : null, + siteSlug: getSiteSlug( state, siteId ), + taskStatuses: get( getSiteChecklist( state, siteId ), [ 'tasks' ], null ), }; }; const mapDispatchToProps = { + loadTrackingTool, track: recordTracksEvent, notify: createNotice, requestTour: requestGuidedTour,