diff --git a/assets/stylesheets/_components.scss b/assets/stylesheets/_components.scss
index 69ac837b4110..02ce2a8a6e44 100644
--- a/assets/stylesheets/_components.scss
+++ b/assets/stylesheets/_components.scss
@@ -13,5 +13,4 @@
@import 'components/date-picker/style';
@import 'components/dialog/style';
@import 'components/main/style';
-@import 'components/segmented-control/style';
@import 'layout/sidebar/style';
diff --git a/client/blocks/comments/post-comment-list.jsx b/client/blocks/comments/post-comment-list.jsx
index 33d8aa328c0e..36fb60a0517d 100644
--- a/client/blocks/comments/post-comment-list.jsx
+++ b/client/blocks/comments/post-comment-list.jsx
@@ -24,7 +24,6 @@ import PostComment from './post-comment';
import PostCommentFormRoot from './form-root';
import CommentCount from './comment-count';
import SegmentedControl from 'components/segmented-control';
-import SegmentedControlItem from 'components/segmented-control/item';
import ConversationFollowButton from 'blocks/conversation-follow-button';
import { shouldShowConversationFollowButton } from 'blocks/conversation-follow-button/helper';
import { getCurrentUserId } from 'state/current-user/selectors';
@@ -421,36 +420,36 @@ class PostCommentList extends React.Component {
) }
{ showFilters && (
-
{ translate( 'All' ) }
-
-
+
{ translate( 'Approved', { context: 'comment status' } ) }
-
-
+
{ translate( 'Pending', { context: 'comment status' } ) }
-
-
+
{ translate( 'Spam', { context: 'comment status' } ) }
-
-
+
{ translate( 'Trash', { context: 'comment status' } ) }
-
+
) }
{ this.renderCommentsList( displayedComments ) }
diff --git a/client/blocks/reader-site-notification-settings/index.jsx b/client/blocks/reader-site-notification-settings/index.jsx
index 5a6d916ba1f3..9b11ea3d2f92 100644
--- a/client/blocks/reader-site-notification-settings/index.jsx
+++ b/client/blocks/reader-site-notification-settings/index.jsx
@@ -14,7 +14,6 @@ import { localize } from 'i18n-calypso';
import Gridicon from 'gridicons';
import ReaderPopover from 'reader/components/reader-popover';
import SegmentedControl from 'components/segmented-control';
-import ControlItem from 'components/segmented-control/item';
import FormToggle from 'components/forms/form-toggle';
import getReaderFollows from 'state/selectors/get-reader-follows';
import {
@@ -194,24 +193,24 @@ class ReaderSiteNotificationSettings extends Component {
{ ! isEmailBlocked && sendNewPostsByEmail && (
-
{ translate( 'Instantly' ) }
-
-
+
{ translate( 'Daily' ) }
-
-
+
{ translate( 'Weekly' ) }
-
+
) }
{ ! isEmailBlocked && (
diff --git a/client/blocks/stats-navigation/intervals.js b/client/blocks/stats-navigation/intervals.js
index 5479260105cb..709200e537ad 100644
--- a/client/blocks/stats-navigation/intervals.js
+++ b/client/blocks/stats-navigation/intervals.js
@@ -11,7 +11,6 @@ import classnames from 'classnames';
*/
import { intervals } from './constants';
import SegmentedControl from 'components/segmented-control';
-import ControlItem from 'components/segmented-control/item';
/**
* Style dependencies
@@ -28,9 +27,9 @@ const Intervals = props => {
{ intervals.map( i => {
const path = pathTemplate.replace( /{{ interval }}/g, i.value );
return (
-
+
{ i.label }
-
+
);
} ) }
diff --git a/client/components/post-schedule/clock.jsx b/client/components/post-schedule/clock.jsx
index 8a10c818a049..5712e5136daf 100644
--- a/client/components/post-schedule/clock.jsx
+++ b/client/components/post-schedule/clock.jsx
@@ -15,7 +15,6 @@ import 'moment-timezone'; // monkey patches the existing moment.js
* Internal dependencies
*/
import SegmentedControl from 'components/segmented-control';
-import ControlItem from 'components/segmented-control/item';
import InfoPopover from 'components/info-popover';
import { withLocalizedMoment } from 'components/localized-moment';
import getSiteSetting from 'state/selectors/get-site-setting';
@@ -219,20 +218,20 @@ class PostScheduleClock extends Component {
value={ date.format( 'A' ) }
/>
-
{ translate( 'AM' ) }
-
-
+
{ translate( 'PM' ) }
-
+
) }
diff --git a/client/components/section-nav/segmented.jsx b/client/components/section-nav/segmented.jsx
index 317cd394da02..99e2219cabaf 100644
--- a/client/components/section-nav/segmented.jsx
+++ b/client/components/section-nav/segmented.jsx
@@ -9,7 +9,6 @@ import classNames from 'classnames';
/**
* Internal Dependencies
*/
-import ControlItem from 'components/segmented-control/item';
import SegmentedControl from 'components/segmented-control';
/**
@@ -17,11 +16,6 @@ import SegmentedControl from 'components/segmented-control';
*/
import './segmented.scss';
-/**
- * Internal variables
- */
-let _instance = 1;
-
class NavSegmented extends Component {
static propTypes = {
label: PropTypes.string,
@@ -32,15 +26,8 @@ class NavSegmented extends Component {
hasSiblingControls: false,
};
- componentWillMount() {
- this.id = _instance;
- _instance++;
- }
-
render() {
- const segmentedClassName = classNames( {
- 'section-nav-group': true,
- 'section-nav__segmented': true,
+ const segmentedClassName = classNames( 'section-nav-group', 'section-nav__segmented', {
'has-siblings': this.props.hasSiblingControls,
} );
@@ -55,19 +42,11 @@ class NavSegmented extends Component {
);
}
- getControlItems = () => {
- return React.Children.map(
- this.props.children,
- function( child, index ) {
- return (
-
- { child.props.children }
-
- );
- },
- this
- );
- };
+ getControlItems() {
+ return React.Children.map( this.props.children, ( child, index ) => (
+
+ ) );
+ }
}
export default NavSegmented;
diff --git a/client/components/segmented-control/README.md b/client/components/segmented-control/README.md
index 4ee3b69f1960..e55bf7a0f564 100644
--- a/client/components/segmented-control/README.md
+++ b/client/components/segmented-control/README.md
@@ -17,7 +17,6 @@ A good example for this case is navigation. Sometimes the option that is selecte
```jsx
import React from 'react';
import SegmentedControl from 'components/segmented-control';
-import SegmentedControlItem from 'components/segmented-control/item';
export default class extends React.Component {
// ...
@@ -25,40 +24,40 @@ export default class extends React.Component {
render() {
return (
-
All
-
+
-
Unread
-
+
-
Comments
-
+
-
Follows
-
+
-
Likes
-
+
);
},
diff --git a/client/components/segmented-control/docs/example.jsx b/client/components/segmented-control/docs/example.jsx
index 5becace04006..4a960bf3523e 100644
--- a/client/components/segmented-control/docs/example.jsx
+++ b/client/components/segmented-control/docs/example.jsx
@@ -1,9 +1,6 @@
-/** @format */
-
/**
* External dependencies
*/
-
import React from 'react';
/**
@@ -11,7 +8,6 @@ import React from 'react';
*/
import SegmentedControl from 'components/segmented-control';
import SimplifiedSegmentedControl from 'components/segmented-control/simplified';
-import ControlItem from 'components/segmented-control/item';
class SegmentedControlDemo extends React.PureComponent {
static displayName = 'SegmentedControl';
@@ -36,13 +32,13 @@ class SegmentedControlDemo extends React.PureComponent {
};
render() {
- var controlDemoStyles = { maxWidth: 386 };
+ const controlDemoStyles = { maxWidth: 386 };
return (
-
+
+
Items passed as options prop
-
All
-
+
-
Unread
-
+
-
Comments
-
+
-
Follows
-
+
-
Likes
-
+
Three items
@@ -101,26 +97,26 @@ class SegmentedControlDemo extends React.PureComponent {
selectedText={ this.state.childSelected }
style={ { maxWidth: 280 } }
>
-
All
-
+
-
Unread
-
+
-
Comments
-
+
);
@@ -131,10 +127,12 @@ class SegmentedControlDemo extends React.PureComponent {
this.setState( {
childSelected: childSelected,
} );
+ // eslint-disable-next-line no-console
console.log( 'Segmented Control (selected):', childSelected );
};
selectSegment = option => {
+ // eslint-disable-next-line no-console
console.log( 'Segmented Control (selected):', option );
};
}
diff --git a/client/components/segmented-control/index.jsx b/client/components/segmented-control/index.jsx
index e54a264cc073..12dc11496a3a 100644
--- a/client/components/segmented-control/index.jsx
+++ b/client/components/segmented-control/index.jsx
@@ -7,13 +7,25 @@ import PropTypes from 'prop-types';
import React from 'react';
import classNames from 'classnames';
+/**
+ * Internal dependencies
+ */
+import SegmentedControlItem from './item';
+
+/**
+ * Style dependencies
+ */
+import './style.scss';
+
export default class SegmentedControl extends React.Component {
+ static Item = SegmentedControlItem;
+
static propTypes = {
- children: PropTypes.node.isRequired,
className: PropTypes.string,
compact: PropTypes.bool,
- onSelect: PropTypes.func,
+ primary: PropTypes.bool,
style: PropTypes.object,
+ children: PropTypes.node.isRequired,
};
render() {
diff --git a/client/components/segmented-control/simplified.jsx b/client/components/segmented-control/simplified.jsx
index e4d47b17fba2..d2ac70656f5b 100644
--- a/client/components/segmented-control/simplified.jsx
+++ b/client/components/segmented-control/simplified.jsx
@@ -3,64 +3,56 @@
/**
* External dependencies
*/
+import React, { useState } from 'react';
import PropTypes from 'prop-types';
-import React from 'react';
-import classNames from 'classnames';
+import { noop } from 'lodash';
/**
* Internal dependencies
*/
-import ControlItem from 'components/segmented-control/item';
+import SegmentedControl from '.';
-export default class SimplifiedSegmentedControl extends React.Component {
- static propTypes = {
- className: PropTypes.string,
- compact: PropTypes.bool,
- initialSelected: PropTypes.string,
- onSelect: PropTypes.func,
- options: PropTypes.arrayOf(
- PropTypes.shape( {
- value: PropTypes.string.isRequired,
- label: PropTypes.string.isRequired,
- path: PropTypes.string,
- } )
- ).isRequired,
- style: PropTypes.object,
- };
- state = { selected: this.props.initialSelected || this.props.options[ 0 ].value };
+function SimplifiedSegmentedControl( {
+ options,
+ initialSelected = options[ 0 ].value,
+ onSelect = noop,
+ ...props
+} ) {
+ const [ selected, setSelected ] = useState( initialSelected );
- renderOptions() {
- return this.props.options.map( ( option, index ) => (
- {
- this.setState( { selected: option.value } );
- this.props.onSelect && this.props.onSelect( option );
- } }
- path={ option.path }
- selected={ this.state.selected === option.value }
- value={ option.value }
- >
- { option.label }
-
- ) );
- }
+ const renderedOptions = options.map( ( option, index ) => (
+ {
+ setSelected( option.value );
+ onSelect( option );
+ } }
+ path={ option.path }
+ selected={ selected === option.value }
+ value={ option.value }
+ >
+ { option.label }
+
+ ) );
- render() {
- const segmentedClasses = {
- 'is-compact': this.props.compact,
- 'is-primary': this.props.primary,
- };
-
- return (
-
- { this.renderOptions() }
-
- );
- }
+ return { renderedOptions };
}
+
+SimplifiedSegmentedControl.propTypes = {
+ className: PropTypes.string,
+ compact: PropTypes.bool,
+ primary: PropTypes.bool,
+ style: PropTypes.object,
+ initialSelected: PropTypes.string,
+ onSelect: PropTypes.func,
+ options: PropTypes.arrayOf(
+ PropTypes.shape( {
+ value: PropTypes.string.isRequired,
+ label: PropTypes.string.isRequired,
+ path: PropTypes.string,
+ } )
+ ).isRequired,
+};
+
+export default SimplifiedSegmentedControl;
diff --git a/client/extensions/woocommerce/app/settings/payments/stripe/payment-method-stripe-connect-prompt.js b/client/extensions/woocommerce/app/settings/payments/stripe/payment-method-stripe-connect-prompt.js
index 4e6faf4d02c3..fbcabd285b4c 100644
--- a/client/extensions/woocommerce/app/settings/payments/stripe/payment-method-stripe-connect-prompt.js
+++ b/client/extensions/woocommerce/app/settings/payments/stripe/payment-method-stripe-connect-prompt.js
@@ -22,7 +22,7 @@ class StripeConnectPrompt extends Component {
onSelectConnect: PropTypes.func.isRequired,
};
- render = () => {
+ render() {
const { isCreateSelected, onSelectCreate, onSelectConnect, translate } = this.props;
return (
@@ -54,7 +54,7 @@ class StripeConnectPrompt extends Component {
);
- };
+ }
}
export default localize( StripeConnectPrompt );
diff --git a/client/extensions/woocommerce/components/test-live-toggle/index.js b/client/extensions/woocommerce/components/test-live-toggle/index.js
index c6e4473b711b..9e83f75e7213 100644
--- a/client/extensions/woocommerce/components/test-live-toggle/index.js
+++ b/client/extensions/woocommerce/components/test-live-toggle/index.js
@@ -11,7 +11,6 @@ import { localize } from 'i18n-calypso';
/**
* Internal dependencies
*/
-import ControlItem from 'components/segmented-control/item';
import FormLabel from 'components/forms/form-label';
import SegmentedControl from 'components/segmented-control';
@@ -22,23 +21,23 @@ class TestLiveToggle extends Component {
onSelectTest: PropTypes.func.isRequired,
};
- render = () => {
+ render() {
const { isTestMode, onSelectLive, onSelectTest, translate } = this.props;
return (
{ translate( 'Payment Mode' ) }
-
+
{ translate( 'Test Mode' ) }
-
-
+
+
{ translate( 'Live Mode' ) }
-
+
);
- };
+ }
}
export default localize( TestLiveToggle );
diff --git a/client/me/help/help-contact-form/index.jsx b/client/me/help/help-contact-form/index.jsx
index b9f5d275a847..d76f89d52e3d 100644
--- a/client/me/help/help-contact-form/index.jsx
+++ b/client/me/help/help-contact-form/index.jsx
@@ -19,7 +19,6 @@ import { preventWidows } from 'lib/formatting';
import config from 'config';
import FormLabel from 'components/forms/form-label';
import SegmentedControl from 'components/segmented-control';
-import ControlItem from 'components/segmented-control/item';
import SelectDropdown from 'components/select-dropdown';
import FormTextarea from 'components/forms/form-textarea';
import FormTextInput from 'components/forms/form-text-input';
@@ -226,10 +225,10 @@ export class HelpContactForm extends React.PureComponent {
{ options.map( option => (
-
+
{ option.label }
{ option.subtext }
-
+
) ) }
{
const { postId } = this.props;
- const appendPostId = !! postId ? `/${ postId }` : '';
+ const appendPostId = postId ? `/${ postId }` : '';
return 'unapproved' !== status
? `/comments/${ status }/${ this.props.siteFragment }${ appendPostId }`
@@ -147,7 +146,7 @@ export class CommentNavigation extends Component {
newStatus,
selectedComments.length,
queryStatus,
- !! isPostView ? 'post' : 'site'
+ isPostView ? 'post' : 'site'
);
this.showBulkNotice( newStatus );
toggleBulkMode();
@@ -299,16 +298,22 @@ export class CommentNavigation extends Component {
{ isCommentsTreeSupported && hasComments && (
-
+
{ translate( 'Newest', {
comment: 'Chronological order for sorting the comments list.',
} ) }
-
-
+
+
{ translate( 'Oldest', {
comment: 'Chronological order for sorting the comments list.',
} ) }
-
+
) }
diff --git a/client/my-sites/media-library/scale.jsx b/client/my-sites/media-library/scale.jsx
index 1081f1da019c..6e1cbd922a59 100644
--- a/client/my-sites/media-library/scale.jsx
+++ b/client/my-sites/media-library/scale.jsx
@@ -16,7 +16,6 @@ import Gridicon from 'gridicons';
*/
import FormRange from 'components/forms/range';
import SegmentedControl from 'components/segmented-control';
-import SegmentedControlItem from 'components/segmented-control/item';
import { setPreference, savePreference } from 'state/preferences/actions';
import { getPreference } from 'state/preferences/selectors';
import { SCALE_CHOICES } from 'lib/media/constants';
@@ -116,20 +115,20 @@ class MediaLibraryScale extends Component {
return (
-
-
-
+
-
+
-
{ translate( 'Monthly billing' ) }
-
+
-
{ translate( 'Yearly billing' ) }
-
+
);
}
@@ -323,19 +322,19 @@ export class PlansFeaturesMain extends Component {
return (
-
{ translate( 'Blogs and Personal Sites' ) }
-
+
-
{ translate( 'Business Sites and Online Stores' ) }
-
+
);
}
diff --git a/client/my-sites/plans-features-main/test/index.jsx b/client/my-sites/plans-features-main/test/index.jsx
index 266dc14d044d..15f35452fcc0 100644
--- a/client/my-sites/plans-features-main/test/index.jsx
+++ b/client/my-sites/plans-features-main/test/index.jsx
@@ -19,8 +19,6 @@ jest.mock( 'components/happychat/connection-connected', () => 'HappychatConnecti
jest.mock( 'components/data/query-plans', () => 'QueryPlans' );
jest.mock( 'components/data/query-site-plans', () => 'QuerySitePlans' );
jest.mock( 'components/data/cart', () => 'CartData' );
-jest.mock( 'components/segmented-control', () => 'SegmentedControl' );
-jest.mock( 'components/segmented-control/item', () => 'SegmentedControlItem' );
jest.mock( 'blocks/payment-methods', () => 'PaymentMethods' );
jest.mock( 'components/main', () => 'MainComponent' );
jest.mock( 'components/popover', () => 'Popover' );
diff --git a/client/my-sites/stats/stats-post-summary/index.jsx b/client/my-sites/stats/stats-post-summary/index.jsx
index 77b52da95923..f352c5eac89c 100644
--- a/client/my-sites/stats/stats-post-summary/index.jsx
+++ b/client/my-sites/stats/stats-post-summary/index.jsx
@@ -16,7 +16,6 @@ import { findIndex, findLastIndex, flatten, flowRight, get, range } from 'lodash
import SummaryChart from '../stats-summary';
import SectionNav from 'components/section-nav';
import SegmentedControl from 'components/segmented-control';
-import ControlItem from 'components/segmented-control/item';
import QueryPostStats from 'components/data/query-post-stats';
import { getPostStats, isRequestingPostStats } from 'state/stats/posts/selectors';
@@ -82,7 +81,7 @@ class StatsPostSummary extends Component {
value: stats.years[ year ].total,
};
} );
- case 'month':
+ case 'month': {
if ( ! stats.years ) {
return [];
}
@@ -103,6 +102,7 @@ class StatsPostSummary extends Component {
const lastNotEmpty = findLastIndex( months, item => item.value !== 0 );
return months.slice( firstNotEmpty, lastNotEmpty + 1 );
+ }
case 'week':
if ( ! stats.weeks ) {
return [];
@@ -141,13 +141,13 @@ class StatsPostSummary extends Component {
{ periods.map( ( { id, label } ) => (
-
{ label }
-
+
) ) }
diff --git a/client/post-editor/editor-revisions-list/view-buttons.jsx b/client/post-editor/editor-revisions-list/view-buttons.jsx
index e275a5ab3094..14d9508360b3 100644
--- a/client/post-editor/editor-revisions-list/view-buttons.jsx
+++ b/client/post-editor/editor-revisions-list/view-buttons.jsx
@@ -6,36 +6,37 @@
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
-import { localize } from 'i18n-calypso';
+import { useTranslate } from 'i18n-calypso';
/**
* Internal dependencies
*/
import SegmentedControl from 'components/segmented-control';
-import ControlItem from 'components/segmented-control/item';
import {
splitPostRevisionsDiffView,
unifyPostRevisionsDiffView,
} from 'state/posts/revisions/actions';
import getPostRevisionsDiffView from 'state/selectors/get-post-revisions-diff-view';
-const EditorRevisionsListViewButtons = ( { translate, diffView, viewSplit, viewUnified } ) => {
+const EditorRevisionsListViewButtons = ( { diffView, viewSplit, viewUnified } ) => {
+ const translate = useTranslate();
+
return (
-
{ translate( 'Unified' ) }
-
-
+
{ translate( 'Split' ) }
-
+
);
};
@@ -58,4 +59,4 @@ const mapDispatchToProps = {
export default connect(
mapStateToProps,
mapDispatchToProps
-)( localize( EditorRevisionsListViewButtons ) );
+)( EditorRevisionsListViewButtons );
diff --git a/client/post-editor/media-modal/gallery/preview.jsx b/client/post-editor/media-modal/gallery/preview.jsx
index d58d716f52c2..b2917d22b332 100644
--- a/client/post-editor/media-modal/gallery/preview.jsx
+++ b/client/post-editor/media-modal/gallery/preview.jsx
@@ -14,7 +14,6 @@ import { noop } from 'lodash';
*/
import Notice from 'components/notice';
import SegmentedControl from 'components/segmented-control';
-import SegmentedControlItem from 'components/segmented-control/item';
import EditorMediaModalGalleryEdit from './edit';
import EditorMediaModalGalleryPreviewShortcode from './preview-shortcode';
import EditorMediaModalGalleryPreviewIndividual from './preview-individual';
@@ -46,18 +45,18 @@ class EditorMediaModalGalleryPreview extends Component {
return (
- this.setState( { isEditing: false } ) }
>
{ translate( 'Preview' ) }
-
-
+ this.setState( { isEditing: true } ) }
>
{ translate( 'Edit' ) }
-
+
);
}
@@ -109,6 +108,4 @@ class EditorMediaModalGalleryPreview extends Component {
}
}
-EditorMediaModalGalleryPreview.displayName = 'EditorMediaModalGalleryPreview';
-
export default localize( EditorMediaModalGalleryPreview );
diff --git a/client/post-editor/post-editor.jsx b/client/post-editor/post-editor.jsx
index 53d31fa08d17..7ca9c98bae96 100644
--- a/client/post-editor/post-editor.jsx
+++ b/client/post-editor/post-editor.jsx
@@ -24,7 +24,6 @@ import EditorTitle from 'post-editor/editor-title';
import EditorPageSlug from 'post-editor/editor-page-slug';
import TinyMCE from 'components/tinymce';
import SegmentedControl from 'components/segmented-control';
-import SegmentedControlItem from 'components/segmented-control/item';
import InvalidURLDialog from 'post-editor/invalid-url-dialog';
import RestorePostDialog from 'post-editor/restore-post-dialog';
import VerifyEmailDialog from 'components/email-verification/email-verification-dialog';
@@ -348,20 +347,20 @@ export class PostEditor extends React.Component {
-
{ this.props.translate( 'Visual', { context: 'Editor writing mode' } ) }
-
-
+
HTML
-
+
diff --git a/client/reader/search-stream/index.jsx b/client/reader/search-stream/index.jsx
index 278e810ca448..5d428c603325 100644
--- a/client/reader/search-stream/index.jsx
+++ b/client/reader/search-stream/index.jsx
@@ -14,7 +14,6 @@ import classnames from 'classnames';
* Internal Dependencies
*/
import BlankSuggestions from 'reader/components/reader-blank-suggestions';
-import ControlItem from 'components/segmented-control/item';
import SegmentedControl from 'components/segmented-control';
import CompactCard from 'components/card/compact';
import DocumentHead from 'components/data/document-head';
@@ -176,12 +175,18 @@ class SearchStream extends React.Component {
/>
{ query && (
-
+
{ TEXT_RELEVANCE_SORT }
-
-
+
+
{ TEXT_DATE_SORT }
-
+
) }
diff --git a/client/signup/steps/about/index.jsx b/client/signup/steps/about/index.jsx
index f922faf14562..5e343979fd6d 100644
--- a/client/signup/steps/about/index.jsx
+++ b/client/signup/steps/about/index.jsx
@@ -47,7 +47,6 @@ import FormFieldset from 'components/forms/form-fieldset';
import FormInputCheckbox from 'components/forms/form-checkbox';
import ScreenReaderText from 'components/screen-reader-text';
import SegmentedControl from 'components/segmented-control';
-import ControlItem from 'components/segmented-control/item';
import SiteVerticalsSuggestionSearch from 'components/site-verticals-suggestion-search';
/**
@@ -382,7 +381,7 @@ class AboutStep extends Component {
-
@@ -390,35 +389,35 @@ class AboutStep extends Component {
{ translate( 'How comfortable are you with creating a website?' ) }
1{ translate( 'Beginner' ) }
-
+
-
2
-
+
-
3
-
+
-
4
-
+
-
5{ translate( 'Expert' ) }
-
+