diff options
Diffstat (limited to 'plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard')
27 files changed, 1049 insertions, 0 deletions
diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/button/index.jsx b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/button/index.jsx new file mode 100644 index 00000000..d945554f --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/button/index.jsx @@ -0,0 +1,52 @@ +/** + * External dependencies + */ +import PropTypes from 'prop-types'; +import React from 'react'; +import classNames from 'classnames'; +import { noop } from 'lodash'; + +/** + * Internal dependencies + */ +import './style.scss'; + +export default class Button extends React.Component { + static displayName = 'Button'; + + static propTypes = { + disabled: PropTypes.bool, + compact: PropTypes.bool, + primary: PropTypes.bool, + scary: PropTypes.bool, + type: PropTypes.string, + href: PropTypes.string, + onClick: PropTypes.func, + borderless: PropTypes.bool, + className: PropTypes.string, + }; + + static defaultProps = { + disabled: false, + type: 'button', + onClick: noop, + borderless: false, + }; + + render() { + const element = this.props.href ? 'a' : 'button'; + const { primary, compact, scary, borderless, className, ...props } = this.props; + + const buttonClasses = classNames( { + 'dops-button': true, + 'is-compact': compact, + 'is-primary': primary, + 'is-scary': scary, + 'is-borderless': borderless, + } ); + + props.className = classNames( className, buttonClasses ); + + return React.createElement( element, props, this.props.children ); + } +} diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/card/compact.jsx b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/card/compact.jsx new file mode 100644 index 00000000..7bfacab4 --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/card/compact.jsx @@ -0,0 +1,23 @@ +/** + * External dependencies + */ +import React from 'react'; +import { assign } from 'lodash'; +import classnames from 'classnames'; + +/** + * Internal dependencies + */ +import Card from 'components/card'; + +export default class CompactCard extends React.Component { + static displayName = 'CompactCard'; + + render() { + const props = assign( {}, this.props, { + className: classnames( this.props.className, 'is-compact' ), + } ); + + return <Card { ...props }>{ this.props.children }</Card>; + } +} diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/card/index.jsx b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/card/index.jsx new file mode 100644 index 00000000..e8dbf9e1 --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/card/index.jsx @@ -0,0 +1,141 @@ +/** + * External dependencies + */ +import PropTypes from 'prop-types'; +import React from 'react'; +import classnames from 'classnames'; +import { assign, omit } from 'lodash'; + +/** + * Internal dependencies + */ +// TODO change to our own gridicon component, when instant search is migrated. +import Gridicon from 'gridicons'; + +import './style.scss'; + +class CardSection extends React.Component { + static propTypes = { + title: PropTypes.any, + vertical: PropTypes.any, + style: PropTypes.object, + className: PropTypes.string, + device: PropTypes.oneOf( [ 'desktop', 'tablet', 'phone' ] ), + }; + + static defaultProps = { vertical: null }; + + render() { + return ( + <div + className={ classnames( 'dops-card-section', this.props.className ) } + style={ this.props.style } + > + { this.props.title ? this._renderWithTitle() : this.props.children } + </div> + ); + } + + _renderWithTitle = () => { + const orientation = this.props.vertical ? 'vertical' : 'horizontal'; + const wrapperClassName = 'dops-card-section-orient-' + orientation; + + return ( + <div className={ wrapperClassName }> + <h4 ref="label" className="dops-card-section-label"> + { this.props.title } + </h4> + <div ref="content" className="dops-card-section-content"> + { this.props.children } + </div> + </div> + ); + }; +} + +class CardFooter extends React.Component { + render() { + return <div className="dops-card-footer">{ this.props.children }</div>; + } +} + +class Card extends React.Component { + static propTypes = { + meta: PropTypes.any, + icon: PropTypes.string, + iconLabel: PropTypes.any, + iconColor: PropTypes.string, + style: PropTypes.object, + className: PropTypes.string, + href: PropTypes.string, + onClick: PropTypes.func, + title: PropTypes.string, + tagName: PropTypes.string, + target: PropTypes.string, + compact: PropTypes.bool, + children: PropTypes.node, + }; + + static defaultProps = { + iconColor: '#787878', + className: '', + tagName: 'div', + onClick: () => {}, + }; + + render() { + const className = classnames( 'dops-card', this.props.className, { + 'is-card-link': !! this.props.href, + 'is-compact': this.props.compact, + } ); + + const omitProps = [ 'compact', 'tagName', 'meta', 'iconColor' ]; + + let linkIndicator; + if ( this.props.href ) { + linkIndicator = ( + <Gridicon + className="dops-card__link-indicator" + icon={ this.props.target ? 'external' : 'chevron-right' } + /> + ); + } else { + omitProps.push( 'href', 'target' ); + } + + let fancyTitle; + if ( this.props.title ) { + fancyTitle = ( + <h2 className="dops-card-title"> + { this.props.title } + { this.props.meta && <span className="dops-card-meta">{ this.props.meta }</span> } + { ( this.props.icon || this.props.iconLabel ) && this._renderIcon() } + </h2> + ); + } + + return React.createElement( + this.props.href ? 'a' : this.props.tagName, + assign( omit( this.props, omitProps ), { className } ), + linkIndicator, + fancyTitle, + this.props.children + ); + } + + _renderIcon = () => { + return ( + <span className="dops-card-icon" style={ { color: this.props.iconColor } }> + { this.props.icon && ( + <Gridicon icon={ this.props.icon } style={ { backgroundColor: this.props.iconColor } } /> + ) } + { this.props.iconLabel } + </span> + ); + }; +} + +Card.Section = CardSection; +Card.Footer = CardFooter; + +export default Card; diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/form-toggle/compact.jsx b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/form-toggle/compact.jsx new file mode 100644 index 00000000..72341c8e --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/form-toggle/compact.jsx @@ -0,0 +1,26 @@ +/** + * External dependencies + */ +import React from 'react'; +import classNames from 'classnames'; +import { omit } from 'lodash'; + +/** + * Internal dependencies + */ +import Toggle from 'components/form-toggle'; + +export default class CompactFormToggle extends React.Component { + static displayName = 'CompactFormToggle'; + + render() { + return ( + <Toggle + { ...omit( this.props, 'className' ) } + className={ classNames( this.props.className, 'is-compact' ) } + > + { this.props.children } + </Toggle> + ); + } +} diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/form-toggle/index.jsx b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/form-toggle/index.jsx new file mode 100644 index 00000000..31739fc8 --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/form-toggle/index.jsx @@ -0,0 +1,126 @@ +/* eslint-disable jsx-a11y/click-events-have-key-events */ +/* eslint-disable jsx-a11y/no-static-element-interactions */ + +/** + * External dependencies + */ +import PropTypes from 'prop-types'; +import React, { Component, Fragment } from 'react'; +import classNames from 'classnames'; + +import './style.scss'; + +export default class FormToggle extends Component { + static propTypes = { + onChange: PropTypes.func, + onKeyDown: PropTypes.func, + checked: PropTypes.bool, + disabled: PropTypes.bool, + id: PropTypes.string, + className: PropTypes.string, + toggling: PropTypes.bool, + 'aria-label': PropTypes.string, + children: PropTypes.node, + disabledReason: PropTypes.node, + switchClassNames: PropTypes.string, + labelClassNames: PropTypes.string, + }; + + static defaultProps = { + checked: false, + disabled: false, + onKeyDown: () => {}, + onChange: () => {}, + disabledReason: '', + }; + + state = {}; + + static idNum = 0; + + constructor() { + super( ...arguments ); + + this.onKeyDown = this.onKeyDown.bind( this ); + this.onClick = this.onClick.bind( this ); + this.onLabelClick = this.onLabelClick.bind( this ); + } + + UNSAFE_componentWillMount() { + this.id = this.constructor.idNum++; + } + + onKeyDown( event ) { + if ( this.props.disabled ) { + return; + } + + if ( event.key === 'Enter' || event.key === ' ' ) { + event.preventDefault(); + this.props.onChange(); + } + + this.props.onKeyDown( event ); + } + + onClick() { + if ( ! this.props.disabled ) { + this.props.onChange(); + } + } + + onLabelClick( event ) { + if ( this.props.disabled ) { + return; + } + + const nodeName = event.target.nodeName.toLowerCase(); + if ( nodeName !== 'a' && nodeName !== 'input' && nodeName !== 'select' ) { + event.preventDefault(); + this.props.onChange(); + } + } + + render() { + const id = this.props.id || 'toggle-' + this.id; + const toggleClasses = classNames( 'form-toggle', this.props.className, { + 'is-toggling': this.props.toggling, + } ); + + return ( + <Fragment> + <input + className={ toggleClasses } + type="checkbox" + checked={ this.props.checked } + readOnly={ true } + disabled={ this.props.disabled } + /> + + <span + className={ classNames( 'form-toggle__switch', this.props.switchClassNames ) } + disabled={ this.props.disabled } + id={ id } + onClick={ this.onClick } + onKeyDown={ this.onKeyDown } + role="checkbox" + aria-checked={ this.props.checked } + aria-label={ this.props[ 'aria-label' ] } + tabIndex={ this.props.disabled ? -1 : 0 } + ref="toggleSwitch" + /> + <label + className={ classNames( 'form-toggle__label', this.props.labelClassNames ) } + htmlFor={ id } + > + <span + className={ classNames( 'form-toggle__label-content', this.props.labelClassNames ) } + onClick={ this.onLabelClick } + > + { this.props.children } + </span> + </label> + </Fragment> + ); + } +} diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/global-notices/index.jsx b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/global-notices/index.jsx new file mode 100644 index 00000000..c0df631a --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/global-notices/index.jsx @@ -0,0 +1,55 @@ +/** + * External Dependencies + */ +import React from 'react'; + +/** + * Internal Dependencies + */ +import SimpleNotice from 'components/notice/index.jsx'; +import NoticeAction from 'components/notice/notice-action'; + +import './style.scss'; + +/** + * NoticesList component + * + * @param {*} props - Props + * @returns {React.Component} - NoticesList component + */ +export default function NoticesList( + props = { handleLocalNoticeDismissClick: null, notices: Object.freeze( [] ) } +) { + const noticesList = props.notices.map( function ( notice ) { + const onDismissClick = theNotice => () => { + theNotice && props.handleLocalNoticeDismissClick( theNotice.id ); + }; + return ( + <SimpleNotice + key={ 'notice-' + notice.id } + status={ notice.status } + duration={ notice.duration || null } + text={ notice.text } + isCompact={ notice.isCompact } + onDismissClick={ onDismissClick( notice ) } + showDismiss={ notice.showDismiss } + > + { notice.button && ( + <NoticeAction href={ notice.href } onClick={ onDismissClick( notice ) }> + { notice.button } + </NoticeAction> + ) } + </SimpleNotice> + ); + } ); + + if ( ! noticesList.length ) { + return null; + } + + return ( + <div id={ props.id } className="global-notices"> + { noticesList } + </div> + ); +} diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/global-notices/store/actions.js b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/global-notices/store/actions.js new file mode 100644 index 00000000..09c739d0 --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/global-notices/store/actions.js @@ -0,0 +1,61 @@ +/** + * External dependencies + */ +import { uniqueId } from 'lodash'; +import { __ } from '@wordpress/i18n'; + +export const CREATE_NOTICE = 'CREATE_NOTICE'; +export const REMOVE_NOTICE = 'REMOVE_NOTICE'; + +/** + * Create global notice + * + * @param {*} status - success, error, info or warning. + * @param {*} text - the text to show. + * @param {*} options - Options. + * @returns {object} - action object. + */ +export function createNotice( status, text, options = {} ) { + const notice = { + id: options.id || uniqueId(), + duration: options.duration ?? 2000, + showDismiss: typeof options.showDismiss === 'boolean' ? options.showDismiss : true, + isPersistent: options.isPersistent || false, + displayOnNextPage: options.displayOnNextPage || false, + status: status, + text: text, + }; + + return { + type: CREATE_NOTICE, + notice: notice, + }; +} + +/** + * Remove notice by ID + * + * @param {*} noticeId - noticeID. + * @returns {object} - action object. + */ +export function removeNotice( noticeId ) { + return { type: REMOVE_NOTICE, notice: { id: noticeId } }; +} + +export const successNotice = createNotice.bind( null, 'is-success' ); +export const errorNotice = createNotice.bind( null, 'is-error' ); +export const infoNotice = createNotice.bind( null, 'is-info' ); +export const warningNotice = createNotice.bind( null, 'is-warning' ); +export const updatingNotice = ( text = __( 'Updating settings…', 'jetpack-search-pkg' ) ) => + createNotice( 'is-info', text, { duration: 30000, id: 'search-updating-settings' } ); +export const removeUpdatingNotice = () => removeNotice( 'search-updating-settings' ); + +export default { + createNotice, + removeNotice, + successNotice, + errorNotice, + warningNotice, + updatingNotice, + removeUpdatingNotice, +}; diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/global-notices/store/reducer.js b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/global-notices/store/reducer.js new file mode 100644 index 00000000..e0749197 --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/global-notices/store/reducer.js @@ -0,0 +1,22 @@ +/** + * Internal dependencies + */ +import { CREATE_NOTICE, REMOVE_NOTICE } from './actions'; + +const notices = ( state = { notices: [] }, action ) => { + switch ( action.type ) { + case CREATE_NOTICE: + return { + ...state, + notices: [ ...state.notices, action.notice ], + }; + case REMOVE_NOTICE: + return { + ...state, + notices: state.notices.filter( notice => notice.id !== action.notice.id ), + }; + } + return state; +}; + +export default notices; diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/global-notices/store/selectors.js b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/global-notices/store/selectors.js new file mode 100644 index 00000000..da2d9829 --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/global-notices/store/selectors.js @@ -0,0 +1,5 @@ +const noticeSelectors = { + getNotices: state => state.notices.notices ?? [], +}; + +export default noticeSelectors; diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/notice/index.jsx b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/notice/index.jsx new file mode 100644 index 00000000..9c1b2e88 --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/notice/index.jsx @@ -0,0 +1,136 @@ +/** + * External dependencies + */ +import PropTypes from 'prop-types'; +import React from 'react'; +import classnames from 'classnames'; +import { noop } from 'lodash'; + +/** + * Internal dependencies + */ +// TODO change to our own gridicon component, when instant search is migrated. +import Gridicon from 'gridicons'; +import './style.scss'; + +export default class SimpleNotice extends React.Component { + static displayName = 'SimpleNotice'; + + static defaultProps = { + duration: 0, + status: null, + showDismiss: true, + className: '', + onDismissClick: noop, + }; + + static propTypes = { + // we should validate the allowed statuses + status: PropTypes.string, + showDismiss: PropTypes.bool, + isCompact: PropTypes.bool, + duration: PropTypes.number, + text: PropTypes.oneOfType( [ + PropTypes.oneOfType( [ PropTypes.string, PropTypes.node ] ), + PropTypes.arrayOf( PropTypes.oneOfType( [ PropTypes.string, PropTypes.node ] ) ), + ] ), + icon: PropTypes.string, + onDismissClick: PropTypes.func, + className: PropTypes.string, + }; + + dismissTimeout = null; + + componentDidMount() { + if ( this.props.duration > 0 ) { + this.dismissTimeout = setTimeout( this.props.onDismissClick, this.props.duration ); + } + } + + componentWillUnmount() { + if ( this.dismissTimeout ) { + clearTimeout( this.dismissTimeout ); + } + } + + getIcon = () => { + let icon; + + switch ( this.props.status ) { + case 'is-info': + icon = 'info'; + break; + case 'is-success': + icon = 'checkmark'; + break; + case 'is-error': + icon = 'notice'; + break; + case 'is-warning': + icon = 'notice'; + break; + default: + icon = 'info'; + break; + } + + return icon; + }; + + clearText = text => { + if ( 'string' === typeof text ) { + return text.replace( /(<([^>]+)>)/gi, '' ); + } + return text; + }; + + onKeyDownCallback = callback => event => { + if ( event.which === 13 || event.which === 32 ) { + callback && callback( event ); + } + }; + + render() { + const { + children, + className, + icon, + isCompact, + onDismissClick, + showDismiss = ! isCompact, // by default, show on normal notices, don't show on compact ones + status, + text, + dismissText, + } = this.props; + const classes = classnames( 'dops-notice', status, className, { + 'is-compact': isCompact, + 'is-dismissable': showDismiss, + } ); + + return ( + <div className={ classes }> + <span className="dops-notice__icon-wrapper"> + <Gridicon className="dops-notice__icon" icon={ icon || this.getIcon() } size={ 24 } /> + </span> + <span className="dops-notice__content"> + <span className="dops-notice__text">{ text ? this.clearText( text ) : children }</span> + </span> + { text ? children : null } + { showDismiss && ( + <span + role="button" + onKeyDown={ this.onKeyDownCallback( onDismissClick ) } + tabIndex="0" + className="dops-notice__dismiss" + onClick={ onDismissClick } + > + <Gridicon icon="cross" size={ 24 } /> + <span className="dops-notice__screen-reader-text screen-reader-text"> + { dismissText } + </span> + </span> + ) } + </div> + ); + } +} diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/notice/notice-action.jsx b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/notice/notice-action.jsx new file mode 100644 index 00000000..5a3e8ebb --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/components/notice/notice-action.jsx @@ -0,0 +1,48 @@ +/** + * External dependencies + */ +import PropTypes from 'prop-types'; +import React from 'react'; + +/** + * Internal dependencies + */ +// TODO change to our own gridicon component, when instant search is migrated. +import Gridicon from 'gridicons'; + +import './style.scss'; + +export default class NoticeAction extends React.Component { + static displayName = 'NoticeAction'; + + static propTypes = { + href: PropTypes.string, + onClick: PropTypes.func, + external: PropTypes.bool, + icon: PropTypes.string, + }; + + static defaultProps = { + external: false, + }; + + render() { + const attributes = { + className: 'dops-notice__action', + href: this.props.href, + onClick: this.props.onClick, + }; + + if ( this.props.external ) { + attributes.target = '_blank'; + } + + return ( + <a { ...attributes }> + <span>{ this.props.children }</span> + { this.props.icon && <Gridicon icon={ this.props.icon } size={ 24 } /> } + { this.props.external && <Gridicon icon="external" size={ 24 } /> } + </a> + ); + } +} diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/actions/index.js b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/actions/index.js new file mode 100644 index 00000000..3b831225 --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/actions/index.js @@ -0,0 +1,14 @@ +/** + * Internal dependencies + */ +import siteSettingActions from './jetpack-settings'; +import sitePlanActions from './site-plan'; +import noticeActions from 'components/global-notices/store/actions'; + +const actions = { + ...siteSettingActions, + ...sitePlanActions, + ...noticeActions, +}; + +export default actions; diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/actions/jetpack-settings.js b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/actions/jetpack-settings.js new file mode 100644 index 00000000..acf807a9 --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/actions/jetpack-settings.js @@ -0,0 +1,73 @@ +/** + * Internal dependencies + */ +import { + fetchJetpackSettings, + updateJetpackSettings as updateJetpackSettingsControl, +} from '../controls'; +import { + removeUpdatingNotice, + updatingNotice, + errorNotice, + successNotice, +} from 'components/global-notices/store/actions'; +import { __ } from '@wordpress/i18n'; + +export const SET_JETPACK_SETTINGS = 'SET_JETPACK_SETTINGS'; +export const TOGGLE_SEARCH_MODULE = 'TOGGLE_SEARCH_MODULE'; + +/** + * Yield actions to update Search Settings + * + * @param {object} settings - settings to apply. + * @param {object} oldSettings - Old settings. + * @yields {object} - an action object. + * @returns {object} - an action object. + */ +export function* updateJetpackSettings( settings, oldSettings ) { + try { + yield updatingNotice(); + yield setJetpackSettings( settings ); + yield setUpdatingJetpackSettings(); + yield updateJetpackSettingsControl( settings ); + const updatedSettings = yield fetchJetpackSettings(); + yield setJetpackSettings( updatedSettings ); + return successNotice( __( 'Updated settings.', 'jetpack-search-pkg' ) ); + } catch ( e ) { + yield setJetpackSettings( oldSettings ); + return errorNotice( __( 'Error Update settings…', 'jetpack-search-pkg' ) ); + } finally { + yield removeUpdatingNotice(); + yield setUpdatingJetpackSettingsDone(); + } +} + +/** + * Set state updating action + * + * @returns {object} - an action object. + */ +export function setUpdatingJetpackSettings() { + return setJetpackSettings( { is_updating: true } ); +} + +/** + * Set state updating finished + * + * @returns {object} - an action object. + */ +export function setUpdatingJetpackSettingsDone() { + return setJetpackSettings( { is_updating: false } ); +} + +/** + * Set Jetpack settings action + * + * @param {object} options - Jetpack settings. + * @returns {object} - an action object. + */ +export function setJetpackSettings( options ) { + return { type: SET_JETPACK_SETTINGS, options }; +} + +export default { updateJetpackSettings, setJetpackSettings }; diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/actions/site-plan.js b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/actions/site-plan.js new file mode 100644 index 00000000..b59c630e --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/actions/site-plan.js @@ -0,0 +1,16 @@ +export const SET_SEARCH_PLAN_INFO = 'SET_SEARCH_PLAN_INFO'; + +/** + * Action to set plan info + * + * @param {*} options - plan info. + * @returns {object} - an action object. + */ +export function setSearchPlanInfo( options ) { + return { + type: 'SET_SEARCH_PLAN_INFO', + options, + }; +} + +export default { setSearchPlanInfo }; diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/controls.js b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/controls.js new file mode 100644 index 00000000..055f975c --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/controls.js @@ -0,0 +1,55 @@ +/** + * Internal dependencies + */ +import restApi from '@automattic/jetpack-api'; + +export const FETCH_JETPACK_SETTINGS = 'FETCH_JETPACK_SETTINGS'; +export const UPDATE_JETPACK_SETTINGS = 'UPDATE_JETPACK_SETTINGS'; +export const FETCH_SEARCH_PLAN_INFO = 'FETCH_SEARCH_PLAN_INFO'; + +/** + * fetchJetpackSettings action + * + * @returns {object} - an action object. + */ +export const fetchJetpackSettings = () => { + return { + type: FETCH_JETPACK_SETTINGS, + }; +}; + +/** + * updateJetpackSettings action + * + * @param {*} settings - Jetpack settings object. + * @returns {object} - an action object. + */ +export const updateJetpackSettings = settings => { + return { + type: UPDATE_JETPACK_SETTINGS, + settings, + }; +}; + +/** + * fetchSearchPlanInfo action + * + * @returns {object} - an action object. + */ +export const fetchSearchPlanInfo = () => { + return { + type: FETCH_SEARCH_PLAN_INFO, + }; +}; + +export default { + [ FETCH_JETPACK_SETTINGS ]: function () { + return restApi.fetchSearchSettings(); + }, + [ UPDATE_JETPACK_SETTINGS ]: function ( action ) { + return restApi.updateSearchSettings( action.settings ); + }, + [ FETCH_SEARCH_PLAN_INFO ]: function () { + return restApi.fetchSearchPlanInfo(); + }, +}; diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/index.js b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/index.js new file mode 100644 index 00000000..56b96527 --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/index.js @@ -0,0 +1,18 @@ +/** + * Internal dependencies + */ +import reducer from './reducer'; +import actions from './actions'; +import selectors from './selectors'; +import resolvers from './resolvers'; +import controls from './controls'; + +export const STORE_ID = 'jetpack-search-plugin'; +export const storeConfig = { + reducer, + actions, + selectors, + resolvers, + controls, + initialState: window.JETPACK_SEARCH_DASHBOARD_INITIAL_STATE || {}, +}; diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/reducer/index.js b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/reducer/index.js new file mode 100644 index 00000000..cf734005 --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/reducer/index.js @@ -0,0 +1,23 @@ +/** + * WordPress dependencies + */ +import { combineReducers } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import siteData from './site-data'; +import userData from './user-data'; +import jetpackSettings from './jetpack-settings'; +import sitePlan from './site-plan'; +import notices from 'components/global-notices/store/reducer'; + +const reducer = combineReducers( { + siteData, + jetpackSettings, + sitePlan, + userData, + notices, +} ); + +export default reducer; diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/reducer/jetpack-settings.js b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/reducer/jetpack-settings.js new file mode 100644 index 00000000..1a1fc138 --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/reducer/jetpack-settings.js @@ -0,0 +1,22 @@ +/** + * Internal dependencies + */ +import { SET_JETPACK_SETTINGS } from '../actions/jetpack-settings'; + +const jetpackSettings = ( state = {}, action ) => { + switch ( action.type ) { + case SET_JETPACK_SETTINGS: + return { + ...state, + ...action.options, + is_toggling_module: + state.module_active !== action.options.module_active && !! action.options.is_updating, + is_toggling_instant_search: + state.instant_search_enabled !== action.options.instant_search_enabled && + !! action.options.is_updating, + }; + } + return state; +}; + +export default jetpackSettings; diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/reducer/site-data.js b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/reducer/site-data.js new file mode 100644 index 00000000..8e1a578d --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/reducer/site-data.js @@ -0,0 +1,5 @@ +const siteData = ( state = {} ) => { + return state; +}; + +export default siteData; diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/reducer/site-plan.js b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/reducer/site-plan.js new file mode 100644 index 00000000..9fff3d43 --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/reducer/site-plan.js @@ -0,0 +1,18 @@ +/** + * Internal dependencies + */ +import { SET_SEARCH_PLAN_INFO } from '../actions/site-plan'; + +const sitePlan = ( state = {}, action ) => { + switch ( action.type ) { + case SET_SEARCH_PLAN_INFO: + return { + ...state, + ...action.options, + }; + } + + return state; +}; + +export default sitePlan; diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/reducer/user-data.js b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/reducer/user-data.js new file mode 100644 index 00000000..17af1898 --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/reducer/user-data.js @@ -0,0 +1,5 @@ +const userData = ( state = {} ) => { + return state; +}; + +export default userData; diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/resolvers.js b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/resolvers.js new file mode 100644 index 00000000..3c5272bc --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/resolvers.js @@ -0,0 +1,48 @@ +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import { fetchJetpackSettings, fetchSearchPlanInfo } from './controls'; +import { setJetpackSettings } from './actions/jetpack-settings'; +import { setSearchPlanInfo } from './actions/site-plan'; +import { errorNotice } from '../components/global-notices/store/actions'; + +/** + * Yield actions to get Search Module Status + * + * @yields {object} - an action object. + * @returns {object} - an action object. + */ +export function* getSearchModuleStatus() { + try { + const settings = yield fetchJetpackSettings(); + if ( settings ) { + return setJetpackSettings( settings ); + } + } catch ( e ) { + return errorNotice( __( 'Error fetching settings…', 'jetpack-search-pkg' ) ); + } +} + +/** + * Yield actions to get search plan info + * + * @yields {object} - an action object. + * @returns {object} - an action object. + */ +export function* getSearchPlanInfo() { + try { + const planInfo = yield fetchSearchPlanInfo(); + if ( planInfo ) { + return setSearchPlanInfo( planInfo ); + } + } catch ( e ) { + return errorNotice( __( 'Error fetching search plan…', 'jetpack-search-pkg' ) ); + } +} + +export default { getSearchModuleStatus, getSearchPlanInfo }; diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/selectors/index.js b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/selectors/index.js new file mode 100644 index 00000000..8020ea19 --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/selectors/index.js @@ -0,0 +1,18 @@ +/** + * Internal dependencies + */ +import siteDataSelectors from './site-data'; +import jetpackSettingSelectors from './jetpack-settings'; +import sitePlanSelectors from './site-plan'; +import userDataSelectors from './user-data'; +import noticeSelectors from 'components/global-notices/store/selectors'; + +const selectors = { + ...siteDataSelectors, + ...jetpackSettingSelectors, + ...sitePlanSelectors, + ...userDataSelectors, + ...noticeSelectors, +}; + +export default selectors; diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/selectors/jetpack-settings.js b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/selectors/jetpack-settings.js new file mode 100644 index 00000000..6cd876c4 --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/selectors/jetpack-settings.js @@ -0,0 +1,10 @@ +const jetpackSettingSelectors = { + getSearchModuleStatus: state => state.jetpackSettings, + isModuleEnabled: state => state.jetpackSettings.module_active, + isInstantSearchEnabled: state => state.jetpackSettings.instant_search_enabled, + isUpdatingJetpackSettings: state => state.jetpackSettings.is_updating, + isTogglingModule: state => state.jetpackSettings.is_toggling_module, + isTogglingInstantSearch: state => state.jetpackSettings.is_toggling_instant_search, +}; + +export default jetpackSettingSelectors; diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/selectors/site-data.js b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/selectors/site-data.js new file mode 100644 index 00000000..5669e52d --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/selectors/site-data.js @@ -0,0 +1,12 @@ +const siteDataSelectors = { + getAPIRootUrl: state => state.siteData?.WP_API_root ?? null, + getAPINonce: state => state.siteData?.WP_API_nonce ?? null, + getRegistrationNonce: state => state.siteData?.registrationNonce ?? null, + getSiteAdminUrl: state => state.siteData?.adminUrl ?? null, + isInstantSearchPromotionActive: state => state.siteData?.showPromotions ?? true, + getBlogId: state => state.siteData?.blogId ?? 0, + getVersion: state => state.siteData?.version ?? 'development', + getCalypsoSlug: state => state.siteData?.calypsoSlug, +}; + +export default siteDataSelectors; diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/selectors/site-plan.js b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/selectors/site-plan.js new file mode 100644 index 00000000..32d24989 --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/selectors/site-plan.js @@ -0,0 +1,12 @@ +const sitePlanSelectors = { + getSearchPlanInfo: state => state.sitePlan, + hasBusinessPlan: state => state.sitePlan.supports_only_classic_search, + hasActiveSearchPurchase: state => state.sitePlan.supports_instant_search, + supportsInstantSearch: state => state.sitePlan.supports_instant_search, + supportsOnlyClassicSearch: state => state.sitePlan.supports_only_classic_search, + getUpgradeBillPeriod: state => state.sitePlan?.default_upgrade_bill_period, + supportsSearch: state => + state.sitePlan.supports_instant_search || state.sitePlan.supports_only_classic_search, +}; + +export default sitePlanSelectors; diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/selectors/user-data.js b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/selectors/user-data.js new file mode 100644 index 00000000..6e5ac9d3 --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-search/src/dashboard/store/selectors/user-data.js @@ -0,0 +1,5 @@ +const userDataSelectors = { + getWpcomUser: state => state.userData?.currentUser?.wpcomUser, +}; + +export default userDataSelectors; |