diff --git a/assets/css/src/components/_welcomeWizard.scss b/assets/css/src/components/_welcomeWizard.scss
index 9b6b3bbdeb..eddff3959a 100644
--- a/assets/css/src/components/_welcomeWizard.scss
+++ b/assets/css/src/components/_welcomeWizard.scss
@@ -121,3 +121,20 @@
position: absolute;
top: -1000px;
}
+
+.mailpoet_welcome_wizard_centered_column {
+ align-items: center;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+}
+
+.mailpoet_wizard_woocommerce_list {
+ text-align: center;
+
+ label {
+ color: #595c65;
+ display: block;
+ margin-top: 10px;
+ }
+}
diff --git a/assets/js/src/wizard/steps/woo_commerce_import_list_step.jsx b/assets/js/src/wizard/steps/woo_commerce_import_list_step.jsx
index 4d429da4ae..182187fbed 100644
--- a/assets/js/src/wizard/steps/woo_commerce_import_list_step.jsx
+++ b/assets/js/src/wizard/steps/woo_commerce_import_list_step.jsx
@@ -1,13 +1,80 @@
import PropTypes from 'prop-types';
import React from 'react';
import MailPoet from 'mailpoet';
+import ReactHtmlParser from 'react-html-parser';
-const WizardWooCommerceImportListStep = props => (
-
-
{MailPoet.I18n.t('wooCommerceListImportTitle')}
-
-);
-WizardWooCommerceImportListStep.propTypes = {};
+class WizardWooCommerceImportListStep extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ importType: null,
+ };
+
+ this.handleOptionChange = this.handleOptionChange.bind(this);
+ this.submit = this.submit.bind(this);
+ }
+
+ handleOptionChange(event) {
+ this.setState({
+ importType: event.target.value,
+ });
+ }
+
+ submit(event) {
+ event.preventDefault();
+ if (!this.state.importType) return false;
+ this.props.submitForm(this.state.importType);
+ return false;
+ }
+
+ render() {
+ return (
+
+
{MailPoet.I18n.t('wooCommerceListImportTitle')}
+
{MailPoet.I18n.t('wooCommerceListImportInfo1')}
+
{MailPoet.I18n.t('wooCommerceListImportInfo2')}
+
{MailPoet.I18n.t('wooCommerceListImportInfo3')}
+
+
+ );
+ }
+}
+
+WizardWooCommerceImportListStep.propTypes = {
+ submitForm: PropTypes.func.isRequired,
+ loading: PropTypes.bool.isRequired,
+};
export default WizardWooCommerceImportListStep;
diff --git a/assets/js/src/wizard/woocommerce_import_controller.jsx b/assets/js/src/wizard/woocommerce_import_controller.jsx
index cadbffdefc..7f74384dd8 100644
--- a/assets/js/src/wizard/woocommerce_import_controller.jsx
+++ b/assets/js/src/wizard/woocommerce_import_controller.jsx
@@ -1,4 +1,3 @@
-import PropTypes from 'prop-types';
import React from 'react';
import MailPoet from 'mailpoet';
import WooCommerceImportListStep from './steps/woo_commerce_import_list_step.jsx';
@@ -6,26 +5,42 @@ import WooCommerceImportListStep from './steps/woo_commerce_import_list_step.jsx
class WooCommerceImportController extends React.Component {
constructor(props) {
super(props);
-
this.state = {
loading: false,
};
this.updateSettings = this.updateSettings.bind(this);
+ this.scheduleImport = this.scheduleImport.bind(this);
+ this.finishWizard = this.finishWizard.bind(this);
+ this.submit = this.submit.bind(this);
}
-
finishWizard() {
this.setState({ loading: true });
window.location = window.finish_wizard_url;
}
updateSettings(data) {
- this.setState({ loading: true });
return MailPoet.Ajax.post({
api_version: window.mailpoet_api_version,
endpoint: 'settings',
action: 'set',
data,
+ }).fail((response) => {
+ this.setState({ loading: false });
+ if (response.errors.length > 0) {
+ MailPoet.Notice.error(
+ response.errors.map(error => error.message),
+ { scroll: true }
+ );
+ }
+ });
+ }
+
+ scheduleImport() {
+ return MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
+ endpoint: 'importExport',
+ action: 'setupWooCommerceInitialImport',
}).then(() => this.setState({ loading: false })).fail((response) => {
this.setState({ loading: false });
if (response.errors.length > 0) {
@@ -37,13 +52,22 @@ class WooCommerceImportController extends React.Component {
});
}
+ submit(importType) {
+ this.setState({ loading: true });
+ const settings = {
+ 'woocommerce.import_screen_displayed': 1,
+ 'mailpoet_subscribe_old_woocommerce_customers.enabled': importType === 'subscribed' ? 1 : 0,
+ };
+ this.updateSettings(settings).then(this.scheduleImport).then(this.finishWizard);
+ }
+
render() {
return (
);
}
diff --git a/lib/API/JSON/v1/ImportExport.php b/lib/API/JSON/v1/ImportExport.php
index 76a5ef16ab..44f82de3b0 100644
--- a/lib/API/JSON/v1/ImportExport.php
+++ b/lib/API/JSON/v1/ImportExport.php
@@ -2,8 +2,11 @@
namespace MailPoet\API\JSON\v1;
+use Carbon\Carbon;
use MailPoet\API\JSON\Endpoint as APIEndpoint;
use MailPoet\Config\AccessControl;
+use MailPoet\Cron\Workers\WooCommerceSync;
+use MailPoet\Models\ScheduledTask;
use MailPoet\Models\Segment;
use MailPoet\Subscribers\ImportExport\Import\MailChimp;
@@ -78,4 +81,27 @@ class ImportExport extends APIEndpoint {
));
}
}
+
+ function setupWooCommerceInitialImport() {
+ try {
+ $task = ScheduledTask::where('type', WooCommerceSync::TASK_TYPE)
+ ->whereRaw('status = ? OR status IS NULL', [ScheduledTask::STATUS_SCHEDULED])
+ ->findOne();
+ if ($task && $task->status === null) {
+ return $this->successResponse();
+ }
+ if (!$task) {
+ $task = ScheduledTask::create();
+ $task->type = WooCommerceSync::TASK_TYPE;
+ $task->status = ScheduledTask::STATUS_SCHEDULED;
+ }
+ $task->scheduled_at = Carbon::createFromTimestamp(current_time('timestamp'));
+ $task->save();
+ return $this->successResponse();
+ } catch (\Exception $e) {
+ return $this->errorResponse([
+ $e->getCode() => $e->getMessage()
+ ]);
+ }
+ }
}
diff --git a/lib/Config/Menu.php b/lib/Config/Menu.php
index bdecacbcd0..cf5fce1aab 100644
--- a/lib/Config/Menu.php
+++ b/lib/Config/Menu.php
@@ -410,7 +410,7 @@ class Menu {
function wooCommerceListImport() {
if ((bool)(defined('DOING_AJAX') && DOING_AJAX)) return;
$data = [
-
+ 'finish_wizard_url' => $this->wp->adminUrl('admin.php?page=' . self::MAIN_PAGE_SLUG),
];
$this->displayPage('woocommerce_list_import.html', $data);
}
diff --git a/tests/integration/API/JSON/v1/ImportExportTest.php b/tests/integration/API/JSON/v1/ImportExportTest.php
new file mode 100644
index 0000000000..595cf69190
--- /dev/null
+++ b/tests/integration/API/JSON/v1/ImportExportTest.php
@@ -0,0 +1,74 @@
+endpoint = ContainerWrapper::getInstance()->get(ImportExport::class);
+ ScheduledTask::where('type', WooCommerceSync::TASK_TYPE)->deleteMany();
+ }
+
+ function testItSchedulesTaskWhenNoneExistss() {
+ $response = $this->endpoint->setupWooCommerceInitialImport();
+ expect($response->status)->equals(200);
+ $task = ScheduledTask::where('type', WooCommerceSync::TASK_TYPE)->findOne();
+ expect($task->status)->equals(ScheduledTask::STATUS_SCHEDULED);
+ $now = time();
+ $scheduled_at = new Carbon($task->scheduled_at);
+ expect($scheduled_at->timestamp)->greaterOrEquals($now - 1);
+ expect($scheduled_at->timestamp)->lessOrEquals($now + 1);
+ }
+
+ function testItReschedulesScheduledTaskToNow() {
+ $original_schedule = Carbon::createFromTimestamp(time() + 3000);
+ $this->createTask(WooCommerceSync::TASK_TYPE, ScheduledTask::STATUS_SCHEDULED, $original_schedule);
+ $this->endpoint->setupWooCommerceInitialImport();
+ $task = ScheduledTask::where('type', WooCommerceSync::TASK_TYPE)->findOne();
+ expect($task->status)->equals(ScheduledTask::STATUS_SCHEDULED);
+ $now = time();
+ $scheduled_at = new Carbon($task->scheduled_at);
+ expect($scheduled_at->timestamp)->greaterOrEquals($now - 1);
+ expect($scheduled_at->timestamp)->lessOrEquals($now + 1);
+ $task_count = ScheduledTask::where('type', WooCommerceSync::TASK_TYPE)->count();
+ expect($task_count)->equals(1);
+ }
+
+ function testItDoesNothingForRunningTask() {
+ $this->createTask(WooCommerceSync::TASK_TYPE, null);
+ $this->endpoint->setupWooCommerceInitialImport();
+ $task = ScheduledTask::where('type', WooCommerceSync::TASK_TYPE)->findOne();
+ expect($task->status)->equals(null);
+ $task_count = ScheduledTask::where('type', WooCommerceSync::TASK_TYPE)->count();
+ expect($task_count)->equals(1);
+ }
+
+ function testItIgnoresCompletedAndPausedTasks() {
+ $this->createTask(WooCommerceSync::TASK_TYPE, ScheduledTask::STATUS_PAUSED);
+ $this->createTask(WooCommerceSync::TASK_TYPE, ScheduledTask::STATUS_COMPLETED);
+ $this->endpoint->setupWooCommerceInitialImport();
+ $task_count = ScheduledTask::where('type', WooCommerceSync::TASK_TYPE)->count();
+ expect($task_count)->equals(3);
+ }
+
+ private function createTask($type, $status = null, $scheduled_at = null) {
+ if (!$scheduled_at) {
+ Carbon::createFromTimestamp(current_time('timestamp'));
+ }
+ $task = ScheduledTask::create();
+ $task->type = $type;
+ $task->status = $status;
+ $task->scheduled_at = $scheduled_at;
+ $task->save();
+ return $task;
+ }
+}
diff --git a/views/woocommerce_list_import.html b/views/woocommerce_list_import.html
index 656b6ede0b..d9cc5274d5 100644
--- a/views/woocommerce_list_import.html
+++ b/views/woocommerce_list_import.html
@@ -12,6 +12,13 @@
<% block translations %>
<%= localize({
-'wooCommerceListImportTitle': __('WooCommerce customers now have their own list'),
+'wooCommerceListImportTitle': _x('WooCommerce customers now have their own list', 'Title on the customers import page'),
+'wooCommerceListImportInfo1': __('MailPoet will create a list of your WooCommerce customers, even those who don’t have an account, known as "Guests".'),
+'wooCommerceListImportInfo2': __('New customers will be able to join this list during checkout. You can manage this new checkout feature in your MailPoet Settings.'),
+'wooCommerceListImportInfo3': __('To begin, please choose how you want to populate your list:'),
+'wooCommerceListImportCheckboxSubscribed': __('add and subscribe all my customers to this list because they agreed to receive marketing emails from me'),
+'wooCommerceListImportCheckboxUnsubscribed': __('add all my customers to the list, but as unsubscribed. They can join this list next time they check out'),
+'wooCommerceListImportInfo4': __('Their subscription preference on other lists won’t be changed.'),
+'wooCommerceListImportSubmit': _x('Create my WooCommerce Customers list now!', 'Submit button caption'),
}) %>
<% endblock %>