2019-02-19 21:07:19 +00:00
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
|
|
|
import { __ } from '@wordpress/i18n';
|
|
|
|
import { Component, Fragment } from '@wordpress/element';
|
2020-12-21 19:06:26 +00:00
|
|
|
import {
|
|
|
|
Button,
|
|
|
|
Card,
|
|
|
|
CardBody,
|
|
|
|
CardFooter,
|
|
|
|
CardHeader,
|
|
|
|
Dashicon,
|
|
|
|
SelectControl,
|
|
|
|
__experimentalText as Text,
|
|
|
|
} from '@wordpress/components';
|
2019-02-19 21:07:19 +00:00
|
|
|
import classnames from 'classnames';
|
2019-02-20 11:50:55 +00:00
|
|
|
import interpolateComponents from 'interpolate-components';
|
2019-03-01 17:20:28 +00:00
|
|
|
import { compose } from '@wordpress/compose';
|
2020-08-18 11:45:42 +00:00
|
|
|
import { withDispatch, withSelect } from '@wordpress/data';
|
2019-03-18 20:41:35 +00:00
|
|
|
import moment from 'moment';
|
2020-05-29 02:32:37 +00:00
|
|
|
import { Icon, chevronLeft, chevronRight } from '@wordpress/icons';
|
2019-10-07 11:51:25 +00:00
|
|
|
import { getSetting } from '@woocommerce/wc-admin-settings';
|
2020-09-03 21:45:40 +00:00
|
|
|
import { NOTES_STORE_NAME, QUERY_DEFAULTS } from '@woocommerce/data';
|
2020-08-20 04:59:52 +00:00
|
|
|
import { recordEvent } from '@woocommerce/tracks';
|
2019-02-19 21:07:19 +00:00
|
|
|
|
2019-03-01 17:20:28 +00:00
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
2020-08-13 02:05:22 +00:00
|
|
|
import sanitizeHTML from '../../lib/sanitize-html';
|
2019-03-06 22:50:47 +00:00
|
|
|
import StoreAlertsPlaceholder from './placeholder';
|
2019-02-19 21:07:19 +00:00
|
|
|
|
2019-03-01 17:20:28 +00:00
|
|
|
import './style.scss';
|
2019-02-19 21:07:19 +00:00
|
|
|
|
2020-12-21 19:06:26 +00:00
|
|
|
export class StoreAlerts extends Component {
|
2019-02-19 21:07:19 +00:00
|
|
|
constructor( props ) {
|
|
|
|
super( props );
|
2019-02-20 15:25:56 +00:00
|
|
|
const { alerts } = this.props;
|
|
|
|
|
2019-02-19 21:07:19 +00:00
|
|
|
this.state = {
|
2019-02-20 16:18:10 +00:00
|
|
|
currentIndex: alerts ? 0 : null,
|
2019-02-19 21:07:19 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
this.previousAlert = this.previousAlert.bind( this );
|
|
|
|
this.nextAlert = this.nextAlert.bind( this );
|
|
|
|
}
|
|
|
|
|
|
|
|
previousAlert( event ) {
|
|
|
|
event.stopPropagation();
|
2019-02-20 16:18:10 +00:00
|
|
|
const { currentIndex } = this.state;
|
2019-02-19 21:07:19 +00:00
|
|
|
|
2019-02-20 16:18:10 +00:00
|
|
|
if ( currentIndex > 0 ) {
|
2019-02-19 21:07:19 +00:00
|
|
|
this.setState( {
|
2019-02-20 16:18:10 +00:00
|
|
|
currentIndex: currentIndex - 1,
|
2019-02-19 21:07:19 +00:00
|
|
|
} );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nextAlert( event ) {
|
|
|
|
event.stopPropagation();
|
2019-02-20 16:18:10 +00:00
|
|
|
const { alerts } = this.props;
|
|
|
|
const { currentIndex } = this.state;
|
2019-02-19 21:07:19 +00:00
|
|
|
|
2019-02-20 16:18:10 +00:00
|
|
|
if ( currentIndex < alerts.length - 1 ) {
|
2019-02-19 21:07:19 +00:00
|
|
|
this.setState( {
|
2019-02-20 16:18:10 +00:00
|
|
|
currentIndex: currentIndex + 1,
|
2019-02-19 21:07:19 +00:00
|
|
|
} );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-18 19:05:44 +00:00
|
|
|
renderActions( alert ) {
|
2019-05-24 20:22:46 +00:00
|
|
|
const { triggerNoteAction, updateNote } = this.props;
|
2020-02-14 02:23:21 +00:00
|
|
|
const actions = alert.actions.map( ( action ) => {
|
2019-03-18 19:05:44 +00:00
|
|
|
return (
|
|
|
|
<Button
|
|
|
|
key={ action.name }
|
2019-05-21 19:01:55 +00:00
|
|
|
isPrimary={ action.primary }
|
2020-06-11 19:22:20 +00:00
|
|
|
isSecondary={ ! action.primary }
|
2019-05-24 17:05:12 +00:00
|
|
|
href={ action.url || undefined }
|
2019-05-24 20:22:46 +00:00
|
|
|
onClick={ () => triggerNoteAction( alert.id, action.id ) }
|
2019-03-18 19:05:44 +00:00
|
|
|
>
|
|
|
|
{ action.label }
|
|
|
|
</Button>
|
|
|
|
);
|
|
|
|
} );
|
|
|
|
|
2019-03-18 20:41:35 +00:00
|
|
|
// TODO: should "next X" be the start, or exactly 1X from the current date?
|
2019-03-18 19:05:44 +00:00
|
|
|
const snoozeOptions = [
|
|
|
|
{
|
2020-07-28 02:32:58 +00:00
|
|
|
value: moment().add( 4, 'hours' ).unix().toString(),
|
2019-03-18 19:05:44 +00:00
|
|
|
label: __( 'Later Today', 'woocommerce-admin' ),
|
|
|
|
},
|
|
|
|
{
|
2019-12-13 17:35:29 +00:00
|
|
|
value: moment()
|
2019-03-18 20:41:35 +00:00
|
|
|
.add( 1, 'day' )
|
|
|
|
.hour( 9 )
|
|
|
|
.minute( 0 )
|
|
|
|
.second( 0 )
|
|
|
|
.millisecond( 0 )
|
2019-12-13 17:35:29 +00:00
|
|
|
.unix()
|
|
|
|
.toString(),
|
2019-03-18 19:05:44 +00:00
|
|
|
label: __( 'Tomorrow', 'woocommerce-admin' ),
|
|
|
|
},
|
|
|
|
{
|
2019-12-13 17:35:29 +00:00
|
|
|
value: moment()
|
2019-03-18 20:41:35 +00:00
|
|
|
.add( 1, 'week' )
|
|
|
|
.hour( 9 )
|
|
|
|
.minute( 0 )
|
|
|
|
.second( 0 )
|
|
|
|
.millisecond( 0 )
|
2019-12-13 17:35:29 +00:00
|
|
|
.unix()
|
|
|
|
.toString(),
|
2019-03-18 19:05:44 +00:00
|
|
|
label: __( 'Next Week', 'woocommerce-admin' ),
|
|
|
|
},
|
|
|
|
{
|
2019-12-13 17:35:29 +00:00
|
|
|
value: moment()
|
2019-03-18 20:41:35 +00:00
|
|
|
.add( 1, 'month' )
|
|
|
|
.hour( 9 )
|
|
|
|
.minute( 0 )
|
|
|
|
.second( 0 )
|
|
|
|
.millisecond( 0 )
|
2019-12-13 17:35:29 +00:00
|
|
|
.unix()
|
|
|
|
.toString(),
|
2019-03-18 19:05:44 +00:00
|
|
|
label: __( 'Next Month', 'woocommerce-admin' ),
|
|
|
|
},
|
|
|
|
];
|
|
|
|
|
2020-02-14 02:23:21 +00:00
|
|
|
const setReminderDate = ( snoozeOption ) => {
|
|
|
|
updateNote( alert.id, {
|
|
|
|
status: 'snoozed',
|
|
|
|
date_reminder: snoozeOption.value,
|
|
|
|
} );
|
2019-12-13 17:35:29 +00:00
|
|
|
|
|
|
|
const eventProps = {
|
|
|
|
alert_name: alert.name,
|
|
|
|
alert_title: alert.title,
|
|
|
|
snooze_duration: snoozeOption.value,
|
|
|
|
snooze_label: snoozeOption.label,
|
2019-03-18 19:05:44 +00:00
|
|
|
};
|
2019-12-13 17:35:29 +00:00
|
|
|
recordEvent( 'store_alert_snooze', eventProps );
|
2019-03-18 19:05:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const snooze = alert.is_snoozable && (
|
2019-12-13 17:35:29 +00:00
|
|
|
<SelectControl
|
2019-03-19 15:50:37 +00:00
|
|
|
className="woocommerce-store-alerts__snooze"
|
2019-12-13 17:35:29 +00:00
|
|
|
options={ [
|
|
|
|
{
|
|
|
|
label: __( 'Remind Me Later', 'woocommerce-admin' ),
|
|
|
|
value: '0',
|
|
|
|
},
|
|
|
|
...snoozeOptions,
|
|
|
|
] }
|
2020-02-14 02:23:21 +00:00
|
|
|
onChange={ ( value ) => {
|
|
|
|
if ( value === '0' ) {
|
2019-12-13 17:35:29 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-02-14 02:23:21 +00:00
|
|
|
const reminderOption = snoozeOptions.find(
|
|
|
|
( option ) => option.value === value
|
|
|
|
);
|
2019-12-13 17:35:29 +00:00
|
|
|
const reminderDate = {
|
|
|
|
value,
|
|
|
|
label: reminderOption && reminderOption.label,
|
|
|
|
};
|
|
|
|
setReminderDate( reminderDate );
|
|
|
|
} }
|
2019-03-18 19:05:44 +00:00
|
|
|
/>
|
|
|
|
);
|
|
|
|
|
|
|
|
if ( actions || snooze ) {
|
|
|
|
return (
|
|
|
|
<div className="woocommerce-store-alerts__actions">
|
|
|
|
{ actions }
|
|
|
|
{ snooze }
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-19 21:07:19 +00:00
|
|
|
render() {
|
2019-03-08 16:17:48 +00:00
|
|
|
const alerts = this.props.alerts || [];
|
2020-02-14 02:23:21 +00:00
|
|
|
const preloadAlertCount = getSetting( 'alertCount', 0, ( count ) =>
|
|
|
|
parseInt( count, 10 )
|
|
|
|
);
|
2019-03-04 13:52:20 +00:00
|
|
|
|
2019-03-12 13:13:20 +00:00
|
|
|
if ( preloadAlertCount > 0 && this.props.isLoading ) {
|
2020-02-14 02:23:21 +00:00
|
|
|
return (
|
|
|
|
<StoreAlertsPlaceholder
|
|
|
|
hasMultipleAlerts={ preloadAlertCount > 1 }
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
} else if ( alerts.length === 0 ) {
|
2019-03-04 13:52:20 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2019-02-20 16:18:10 +00:00
|
|
|
const { currentIndex } = this.state;
|
|
|
|
const numberOfAlerts = alerts.length;
|
2019-03-08 16:17:48 +00:00
|
|
|
const alert = alerts[ currentIndex ];
|
|
|
|
const type = alert.type;
|
2020-12-21 19:06:26 +00:00
|
|
|
const className = classnames( 'woocommerce-store-alerts', {
|
|
|
|
'is-alert-error': type === 'error',
|
|
|
|
'is-alert-update': type === 'update',
|
|
|
|
} );
|
2019-03-12 13:13:20 +00:00
|
|
|
|
2019-03-08 16:17:48 +00:00
|
|
|
return (
|
2020-12-21 19:06:26 +00:00
|
|
|
<Card className={ className } size={ null }>
|
|
|
|
<CardHeader isBorderless>
|
|
|
|
<Text variant="title.medium" as="h2">
|
|
|
|
{ alert.icon && (
|
|
|
|
<Dashicon key="icon" icon={ alert.icon } />
|
|
|
|
) }
|
|
|
|
{ alert.title }
|
|
|
|
</Text>
|
|
|
|
{ numberOfAlerts > 1 && (
|
2019-03-04 13:52:20 +00:00
|
|
|
<div className="woocommerce-store-alerts__pagination">
|
2020-05-29 02:32:37 +00:00
|
|
|
<Button
|
2019-03-04 13:52:20 +00:00
|
|
|
onClick={ this.previousAlert }
|
2020-02-14 02:23:21 +00:00
|
|
|
disabled={ currentIndex === 0 }
|
|
|
|
label={ __(
|
|
|
|
'Previous Alert',
|
|
|
|
'woocommerce-admin'
|
|
|
|
) }
|
2020-05-29 02:32:37 +00:00
|
|
|
>
|
|
|
|
<Icon icon={ chevronLeft } />
|
|
|
|
</Button>
|
2019-03-04 13:52:20 +00:00
|
|
|
<span
|
|
|
|
className="woocommerce-store-alerts__pagination-label"
|
|
|
|
role="status"
|
|
|
|
aria-live="polite"
|
|
|
|
>
|
|
|
|
{ interpolateComponents( {
|
2020-02-14 02:23:21 +00:00
|
|
|
mixedString: __(
|
|
|
|
'{{current /}} of {{total /}}',
|
|
|
|
'woocommerce-admin'
|
|
|
|
),
|
2019-03-04 13:52:20 +00:00
|
|
|
components: {
|
2020-02-14 02:23:21 +00:00
|
|
|
current: (
|
|
|
|
<Fragment>
|
|
|
|
{ currentIndex + 1 }
|
|
|
|
</Fragment>
|
|
|
|
),
|
|
|
|
total: (
|
|
|
|
<Fragment>
|
|
|
|
{ numberOfAlerts }
|
|
|
|
</Fragment>
|
|
|
|
),
|
2019-03-04 13:52:20 +00:00
|
|
|
},
|
|
|
|
} ) }
|
|
|
|
</span>
|
2020-05-29 02:32:37 +00:00
|
|
|
<Button
|
2019-03-04 13:52:20 +00:00
|
|
|
onClick={ this.nextAlert }
|
|
|
|
disabled={ numberOfAlerts - 1 === currentIndex }
|
2020-02-14 02:23:21 +00:00
|
|
|
label={ __(
|
|
|
|
'Next Alert',
|
|
|
|
'woocommerce-admin'
|
|
|
|
) }
|
2020-05-29 02:32:37 +00:00
|
|
|
>
|
|
|
|
<Icon icon={ chevronRight } />
|
|
|
|
</Button>
|
2019-03-04 13:52:20 +00:00
|
|
|
</div>
|
2020-12-21 19:06:26 +00:00
|
|
|
) }
|
|
|
|
</CardHeader>
|
|
|
|
<CardBody>
|
|
|
|
<div
|
|
|
|
className="woocommerce-store-alerts__message"
|
|
|
|
dangerouslySetInnerHTML={ sanitizeHTML(
|
|
|
|
alert.content
|
|
|
|
) }
|
|
|
|
/>
|
|
|
|
</CardBody>
|
|
|
|
<CardFooter isBorderless>
|
|
|
|
{ this.renderActions( alert ) }
|
|
|
|
</CardFooter>
|
2019-03-04 13:52:20 +00:00
|
|
|
</Card>
|
2019-02-19 21:07:19 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-01 17:20:28 +00:00
|
|
|
export default compose(
|
2020-02-14 02:23:21 +00:00
|
|
|
withSelect( ( select ) => {
|
2020-08-13 13:23:38 +00:00
|
|
|
const { getNotes, isResolving } = select( NOTES_STORE_NAME );
|
2019-03-01 17:20:28 +00:00
|
|
|
const alertsQuery = {
|
|
|
|
page: 1,
|
|
|
|
per_page: QUERY_DEFAULTS.pageSize,
|
|
|
|
type: 'error,update',
|
2019-03-12 13:13:20 +00:00
|
|
|
status: 'unactioned',
|
2019-03-01 17:20:28 +00:00
|
|
|
};
|
2019-02-20 15:25:56 +00:00
|
|
|
|
2019-03-12 13:13:20 +00:00
|
|
|
// Filter out notes that may have been marked actioned or not delayed after the initial request
|
2020-02-14 02:23:21 +00:00
|
|
|
const filterNotes = ( note ) => note.status === 'unactioned';
|
2019-03-12 13:13:20 +00:00
|
|
|
const alerts = getNotes( alertsQuery ).filter( filterNotes );
|
2020-08-13 13:23:38 +00:00
|
|
|
const isLoading = isResolving( 'getNotes', [ alertsQuery ] );
|
2019-02-20 16:37:03 +00:00
|
|
|
|
2019-03-12 13:13:20 +00:00
|
|
|
return {
|
|
|
|
alerts,
|
|
|
|
isLoading,
|
|
|
|
};
|
|
|
|
} ),
|
2020-02-14 02:23:21 +00:00
|
|
|
withDispatch( ( dispatch ) => {
|
2020-08-18 11:45:42 +00:00
|
|
|
const { triggerNoteAction, updateNote } = dispatch( NOTES_STORE_NAME );
|
2019-05-24 20:22:46 +00:00
|
|
|
|
2019-03-12 13:13:20 +00:00
|
|
|
return {
|
2019-05-24 20:22:46 +00:00
|
|
|
triggerNoteAction,
|
2019-03-12 13:13:20 +00:00
|
|
|
updateNote,
|
|
|
|
};
|
2019-03-01 17:20:28 +00:00
|
|
|
} )
|
|
|
|
)( StoreAlerts );
|