forked from MichaelYick/mailpoet
Add support for multiple any of for Woo subscriptions segment
[MAILPOET-3956]
This commit is contained in:
parent
c86443a08c
commit
651528c0b6
@ -1,11 +1,14 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import MailPoet from 'mailpoet';
|
||||
import { find } from 'lodash/fp';
|
||||
import { filter } from 'lodash/fp';
|
||||
import { useSelect, useDispatch } from '@wordpress/data';
|
||||
|
||||
import Select from 'common/form/react_select/react_select';
|
||||
import ReactSelect from 'common/form/react_select/react_select';
|
||||
import Select from 'common/form/select/select';
|
||||
import { Grid } from 'common/grid';
|
||||
|
||||
import {
|
||||
AnyValueTypes,
|
||||
SegmentTypes,
|
||||
SelectOption,
|
||||
WindowSubscriptionProducts,
|
||||
@ -21,11 +24,12 @@ export const WooCommerceSubscriptionOptions = [
|
||||
];
|
||||
|
||||
export function validateWooCommerceSubscription(
|
||||
formItems: WooCommerceSubscriptionFormItem
|
||||
formItem: WooCommerceSubscriptionFormItem
|
||||
): boolean {
|
||||
const isIncomplete = !formItem.product_ids || !formItem.product_ids.length || !formItem.operator;
|
||||
if (
|
||||
formItems.action === WooCommerceSubscriptionsActionTypes.ACTIVE_SUBSCRIPTIONS
|
||||
&& !formItems.product_id
|
||||
formItem.action === WooCommerceSubscriptionsActionTypes.ACTIVE_SUBSCRIPTIONS
|
||||
&& isIncomplete
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
@ -42,7 +46,7 @@ export const WooCommerceSubscriptionFields: React.FunctionComponent<Props> = ({
|
||||
[filterIndex]
|
||||
);
|
||||
|
||||
const { updateSegmentFilter } = useDispatch('mailpoet-dynamic-segments-form');
|
||||
const { updateSegmentFilter, updateSegmentFilterFromEvent } = useDispatch('mailpoet-dynamic-segments-form');
|
||||
|
||||
const subscriptionProducts: WindowSubscriptionProducts = useSelect(
|
||||
(select) => select('mailpoet-dynamic-segments-form').getSubscriptionProducts(),
|
||||
@ -53,19 +57,57 @@ export const WooCommerceSubscriptionFields: React.FunctionComponent<Props> = ({
|
||||
label: product.name,
|
||||
}));
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
(segment.action === WooCommerceSubscriptionsActionTypes.ACTIVE_SUBSCRIPTIONS)
|
||||
&& (segment.operator !== AnyValueTypes.ANY)
|
||||
) {
|
||||
updateSegmentFilter({ operator: AnyValueTypes.ANY }, filterIndex);
|
||||
}
|
||||
// Temporary BC fix
|
||||
if (segment.product_id && !segment.product_ids) {
|
||||
updateSegmentFilter({ product_ids: [segment.product_id] }, filterIndex);
|
||||
}
|
||||
}, [updateSegmentFilter, segment, filterIndex]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Select
|
||||
dimension="small"
|
||||
isFullWidth
|
||||
placeholder={MailPoet.I18n.t('selectWooSubscription')}
|
||||
automationId="segment-woo-subscription-action"
|
||||
options={productOptions}
|
||||
value={find(['value', segment.product_id], productOptions)}
|
||||
onChange={(option: SelectOption): void => {
|
||||
updateSegmentFilter({ product_id: option.value }, filterIndex);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<>
|
||||
<Grid.CenteredRow>
|
||||
<Select
|
||||
key="select-operator"
|
||||
value={segment.operator}
|
||||
onChange={(e) => updateSegmentFilterFromEvent(
|
||||
'operator',
|
||||
filterIndex,
|
||||
e
|
||||
)}
|
||||
automationId="select-operator"
|
||||
>
|
||||
<option value={AnyValueTypes.ANY}>{MailPoet.I18n.t('anyOf')}</option>
|
||||
</Select>
|
||||
</Grid.CenteredRow>
|
||||
<Grid.CenteredRow>
|
||||
<ReactSelect
|
||||
isMulti
|
||||
dimension="small"
|
||||
key="select-segment-category"
|
||||
isFullWidth
|
||||
placeholder={MailPoet.I18n.t('selectWooSubscription')}
|
||||
options={productOptions}
|
||||
value={filter(
|
||||
(option) => {
|
||||
if (!segment.product_ids) return false;
|
||||
return segment.product_ids.indexOf(option.value) !== -1;
|
||||
},
|
||||
productOptions
|
||||
)}
|
||||
onChange={(options: SelectOption[]): void => updateSegmentFilter(
|
||||
{ product_ids: (options || []).map((x: SelectOption) => x.value) },
|
||||
filterIndex
|
||||
)}
|
||||
automationId="select-segment-products"
|
||||
/>
|
||||
</Grid.CenteredRow>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -85,6 +85,8 @@ export interface WooCommerceFormItem extends FormItem {
|
||||
|
||||
export interface WooCommerceSubscriptionFormItem extends FormItem {
|
||||
product_id?: string;
|
||||
product_ids?: string[];
|
||||
operator?: AnyValueTypes;
|
||||
}
|
||||
|
||||
export interface EmailFormItem extends FormItem {
|
||||
|
@ -223,8 +223,10 @@ class FilterDataMapper {
|
||||
$filterType = DynamicSegmentFilterData::TYPE_WOOCOMMERCE_SUBSCRIPTION;
|
||||
$action = $data['action'];
|
||||
if ($data['action'] === WooCommerceSubscription::ACTION_HAS_ACTIVE) {
|
||||
if (!isset($data['product_id'])) throw new InvalidFilterException('Missing product', InvalidFilterException::MISSING_PRODUCT_ID);
|
||||
$filterData['product_id'] = $data['product_id'];
|
||||
if (!isset($data['product_ids']) || !is_array($data['product_ids'])) throw new InvalidFilterException('Missing product', InvalidFilterException::MISSING_PRODUCT_ID);
|
||||
if (!isset($data['operator'])) throw new InvalidFilterException('Missing operator', InvalidFilterException::MISSING_OPERATOR);
|
||||
$filterData['operator'] = $data['operator'];
|
||||
$filterData['product_ids'] = $data['product_ids'];
|
||||
} else {
|
||||
throw new InvalidFilterException("Unknown action " . $data['action'], InvalidFilterException::MISSING_ACTION);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ namespace MailPoet\Segments\DynamicSegments\Filters;
|
||||
use MailPoet\Entities\DynamicSegmentFilterEntity;
|
||||
use MailPoet\Entities\SubscriberEntity;
|
||||
use MailPoet\Util\Security;
|
||||
use MailPoetVendor\Doctrine\DBAL\Connection;
|
||||
use MailPoetVendor\Doctrine\DBAL\Query\QueryBuilder;
|
||||
use MailPoetVendor\Doctrine\ORM\EntityManager;
|
||||
|
||||
@ -23,7 +24,11 @@ class WooCommerceSubscription implements Filter {
|
||||
public function apply(QueryBuilder $queryBuilder, DynamicSegmentFilterEntity $filter): QueryBuilder {
|
||||
global $wpdb;
|
||||
$filterData = $filter->getFilterData();
|
||||
$productId = (int)$filterData->getParam('product_id');
|
||||
$productIds = $filterData->getParam('product_ids');
|
||||
// Temporary BC fix
|
||||
if (!$productIds) {
|
||||
$productIds = [(int)$filterData->getParam('product_id')];
|
||||
}
|
||||
$subscribersTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName();
|
||||
$parameterSuffix = $filter->getId() ?: Security::generateRandomString();
|
||||
return $queryBuilder->innerJoin(
|
||||
@ -45,7 +50,7 @@ class WooCommerceSubscription implements Filter {
|
||||
'items',
|
||||
$wpdb->prefix . 'woocommerce_order_itemmeta',
|
||||
'itemmeta',
|
||||
"itemmeta.order_item_id=items.order_item_id AND itemmeta.meta_key='_product_id' AND itemmeta.meta_value=:product" . $parameterSuffix
|
||||
)->setParameter('product' . $parameterSuffix, $productId);
|
||||
"itemmeta.order_item_id=items.order_item_id AND itemmeta.meta_key='_product_id' AND itemmeta.meta_value IN (:products" . $parameterSuffix . ")"
|
||||
)->setParameter('products' . $parameterSuffix, $productIds, Connection::PARAM_STR_ARRAY);
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ class WooCommerceSubscriptionsSegmentCest {
|
||||
$i->fillField(['name' => 'name'], $segmentTitle);
|
||||
$i->fillField(['name' => 'description'], 'Desc ' . $segmentTitle);
|
||||
$i->selectOptionInReactSelect('has an active subscription', $segmentActionSelectElement);
|
||||
$i->selectOptionInReactSelect('Subscription 1', '[data-automation-id="segment-woo-subscription-action"]');
|
||||
$i->selectOptionInReactSelect('Subscription 1', '[data-automation-id="select-segment-products"]');
|
||||
$i->waitForText('Calculating segment size…');
|
||||
$i->waitForText('This segment has 2 subscribers.');
|
||||
$i->seeNoJSErrors();
|
||||
|
@ -373,7 +373,8 @@ class FilterDataMapperTest extends \MailPoetUnitTest {
|
||||
$data = ['filters' => [[
|
||||
'segmentType' => DynamicSegmentFilterData::TYPE_WOOCOMMERCE_SUBSCRIPTION,
|
||||
'action' => WooCommerceSubscription::ACTION_HAS_ACTIVE,
|
||||
'product_id' => '10',
|
||||
'operator' => DynamicSegmentFilterData::OPERATOR_ANY,
|
||||
'product_ids' => ['10'],
|
||||
'some_mess' => 'mess',
|
||||
]]];
|
||||
$filters = $this->mapper->map($data);
|
||||
@ -385,7 +386,8 @@ class FilterDataMapperTest extends \MailPoetUnitTest {
|
||||
expect($filter->getFilterType())->equals(DynamicSegmentFilterData::TYPE_WOOCOMMERCE_SUBSCRIPTION);
|
||||
expect($filter->getAction())->equals(WooCommerceSubscription::ACTION_HAS_ACTIVE);
|
||||
expect($filter->getData())->equals([
|
||||
'product_id' => '10',
|
||||
'product_ids' => ['10'],
|
||||
'operator' => DynamicSegmentFilterData::OPERATOR_ANY,
|
||||
'connect' => DynamicSegmentFilterData::CONNECT_TYPE_AND,
|
||||
]);
|
||||
}
|
||||
@ -396,12 +398,25 @@ class FilterDataMapperTest extends \MailPoetUnitTest {
|
||||
$this->expectExceptionCode(InvalidFilterException::MISSING_ACTION);
|
||||
$data = ['filters' => [[
|
||||
'segmentType' => DynamicSegmentFilterData::TYPE_WOOCOMMERCE_SUBSCRIPTION,
|
||||
'product_id' => '10',
|
||||
'operator' => DynamicSegmentFilterData::OPERATOR_ANY,
|
||||
'product_ids' => ['10'],
|
||||
]]];
|
||||
$this->mapper->map($data);
|
||||
}
|
||||
|
||||
public function testItChecksWooCommerceSubscriptionProductId() {
|
||||
public function testItChecksWooCommerceSubscriptionProductIds() {
|
||||
$this->expectException(InvalidFilterException::class);
|
||||
$this->expectExceptionMessage('Missing product');
|
||||
$this->expectExceptionCode(InvalidFilterException::MISSING_PRODUCT_ID);
|
||||
$data = ['filters' => [[
|
||||
'segmentType' => DynamicSegmentFilterData::TYPE_WOOCOMMERCE_SUBSCRIPTION,
|
||||
'action' => WooCommerceSubscription::ACTION_HAS_ACTIVE,
|
||||
'operator' => DynamicSegmentFilterData::OPERATOR_ANY,
|
||||
]]];
|
||||
$this->mapper->map($data);
|
||||
}
|
||||
|
||||
public function testItChecksWooCommerceSubscriptionMissingOperator() {
|
||||
$this->expectException(InvalidFilterException::class);
|
||||
$this->expectExceptionMessage('Missing product');
|
||||
$this->expectExceptionCode(InvalidFilterException::MISSING_PRODUCT_ID);
|
||||
|
Loading…
x
Reference in New Issue
Block a user