Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add A/B testing for "From:" address #648

Merged
merged 6 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 4 additions & 24 deletions ang/crmMosaico/BlockMailing.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,35 +21,15 @@
<div class="form-group">
<label for="inputFrom" ng-class="checkPerm('create mailings') ? 'control-label' : 'control-label required-mark'">{{ts('From')}}
<a crm-ui-help="hs({id: 'from_email', title: ts('From')})"></a></label>
<div ng-controller="EmailAddrCtrl" crm-mailing-from-address="fromPlaceholder" crm-mailing="mailing">
<select
id="inputFrom"
class="form-control"
crm-ui-select="{dropdownAutoWidth : true, allowClear: false}"
name="fromAddress"
ng-model="fromPlaceholder.label"
required>
<option ng-repeat="frm in crmFromAddresses.getAll() | filter:{is_active:1} | orderBy:'weight'"
value="{{frm.label}}">{{frm.label}}
</option>
</select>
<div>
<crm-mosaico-from-list crm-mailing="mailing" />
</div>
</div>

<div class="form-group" ng-show="crmMailingConst.enableReplyTo">
<label for="inputReplyTo" class="control-label">{{ts('Reply-To')}}</label>
<div ng-controller="EmailAddrCtrl">
<select
id="inputReplyTo"
class="form-control"
crm-ui-select="{dropdownAutoWidth : true, allowClear: true, placeholder: ts('Email address')}"
name="replyTo"
ng-change="checkReplyToChange(mailing)"
ng-model="mailing.replyto_email"
>
<option value=""></option>
<option ng-repeat="frm in crmFromAddresses.getAll() | filter:{is_active:1} | orderBy:'weight'" value="{{frm.label}}">{{frm.label}}</option>
</select>
<div>
<crm-mosaico-reply-to-list crm-mailing="mailing" />
</div>
</div>

Expand Down
44 changes: 44 additions & 0 deletions ang/crmMosaico/FromList.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<div class="form-inline" ng-if="!isSplit()">
<div class="form-group">
<span ng-controller="EmailAddrCtrl" crm-mailing-from-address="fromPlaceholder" crm-mailing="mailing">
<select
id="inputFrom"
class="form-control"
name="fromAddress"
ng-model="fromPlaceholder.label"
crm-ui-select="{width: '40em', dropdownAutoWidth : true, allowClear: false}"
required>
<option ng-repeat="frm in crmFromAddresses.getAll() | filter:{is_active:1} | orderBy:'weight'"
value="{{frm.label}}">{{frm.label}}
</option>
</select>
</span>
<a ng-click="addFrom()" class="btn btn-default" title="{{ts('Add alternate \'From\'')}}">
<span><i class="crm-i fa-plus-circle"></i></span>
</a>
</div>
</div>

<div class="form-inline" ng-if="isSplit()">
<div class="form-group" ng-repeat="(vid, variant) in mailing.template_options.variants">
({{labels[vid]}})

<span ng-controller="EmailAddrCtrl" crm-mailing-from-address="fromPlaceholder" crm-mailing="variant">
<select
crm-ui-id="subform.from"
name="fromAddressA"
class="form-control"
ng-model="fromPlaceholder.label"
crm-ui-select="{width: '40em', dropdownAutoWidth : true, allowClear: false}"
required>
<option ng-repeat="frm in crmFromAddresses.getAll() | filter:{is_active:1} | orderBy:'weight'"
value="{{frm.label}}">{{frm.label}}
</option>
</select>
</span>

<a ng-click="rmFrom(vid)" class="btn btn-default" title="{{ts('Remove alternate \'From\'')}}">
<span><i class="crm-i fa-trash"></i></span>
</a>
</div>
</div>
42 changes: 42 additions & 0 deletions ang/crmMosaico/FromList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
(function(angular, $, _) {
// Example usage: <crm-mosaico-from-list crm-mailing="myMailing" />
angular.module('crmMosaico').directive('crmMosaicoFromList', function(crmUiHelp, crmMosaicoVariants) {
return {
scope: {
crmMailing: '@'
},
templateUrl: '~/crmMosaico/FromList.html',
link: function (scope, elm, attr) {
scope.$parent.$watch(attr.crmMailing, function(newValue){
scope.mailing = newValue;
});
scope.ts = CRM.ts(null);
scope.hs = crmUiHelp({file: 'CRM/Mailing/MailingUI'});
scope.checkPerm = CRM.checkPerm;

scope.addFrom = function() {
crmMosaicoVariants.split(scope.mailing, 'from_name');
crmMosaicoVariants.split(scope.mailing, 'from_email');
if (!CRM.crmMailing.enableReplyTo) {
// Ugh. Brain hurts. See also: crmMailingFromAddress (CRM-18364 behavior)
crmMosaicoVariants.split(scope.mailing, 'replyto_email');
}

}
scope.rmFrom = function(vid) {
crmMosaicoVariants.remove(scope.mailing, 'from_email', vid);
crmMosaicoVariants.remove(scope.mailing, 'from_name', vid);
if (!CRM.crmMailing.enableReplyTo) {
// Ugh. Brain hurts. See also: crmMailingFromAddress (CRM-18364 behavior)
crmMosaicoVariants.remove(scope.mailing, 'replyto_email', vid);
}
}
scope.isSplit = function() {
return crmMosaicoVariants.isSplit(scope.mailing, 'from_email')
}
scope.labels = crmMosaicoVariants.getLabels();
}
};

});
})(angular, CRM.$, CRM._);
45 changes: 45 additions & 0 deletions ang/crmMosaico/ReplyToList.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<div class="form-inline" ng-if="!isSplit()">
<div class="form-group">
<span ng-controller="EmailAddrCtrl">
<select
id="inputReplyTo"
class="form-control"
name="replyTo"
ng-change="checkReplyToChange(mailing)"
ng-model="mailing.replyto_email"
crm-ui-select="{width: '40em', dropdownAutoWidth : true, allowClear: true, placeholder: ts('Email address')}"
>
<option value="">(Email address)</option><!-- If you fix crm-ui-select, then this label can be emptied. It functions as placeholder text. -->
<option ng-repeat="frm in crmFromAddresses.getAll() | filter:{is_active:1} | orderBy:'weight'" value="{{frm.label}}">{{frm.label}}</option>
</select>
</span>

<a ng-click="addReplyTo()" class="btn btn-default" title="{{ts('Add alternate \'Reply-To\'')}}">
<span><i class="crm-i fa-plus-circle"></i></span>
</a>
</div>
</div>

<div class="form-inline" ng-if="isSplit()">
<div class="form-group" ng-repeat="(vid, variant) in mailing.template_options.variants">
({{labels[vid]}})

<span ng-controller="EmailAddrCtrl">
<select
id="inputReplyToA"
class="form-control"
name="replyToA"
ng-change="checkReplyToChange(variant)"
ng-model="variant.replyto_email"
crm-ui-select="{width: '40em', dropdownAutoWidth : true, allowClear: true, placeholder: ts('Email address')}"
>
<option value="">(Email address)</option><!-- If you fix crm-ui-select, then this label can be emptied. It functions as placeholder text. -->
<option ng-repeat="frm in crmFromAddresses.getAll() | filter:{is_active:1} | orderBy:'weight'" value="{{frm.label}}">{{frm.label}}</option>
</select>
</span>

<a ng-click="rmReplyTo(vid)" class="btn btn-default" title="{{ts('Remove alternate \'Reply-To\'')}}">
<span><i class="crm-i fa-trash"></i></span>
</a>
</div>
</div>
25 changes: 25 additions & 0 deletions ang/crmMosaico/ReplyToList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
(function(angular, $, _) {
// Example usage: <crm-mosaico-reply-to-list crm-mailing="myMailing" />
angular.module('crmMosaico').directive('crmMosaicoReplyToList', function(crmUiHelp, crmMosaicoVariants) {
return {
scope: {
crmMailing: '@'
},
templateUrl: '~/crmMosaico/ReplyToList.html',
link: function (scope, elm, attr) {
scope.$parent.$watch(attr.crmMailing, function(newValue){
scope.mailing = newValue;
});
scope.ts = CRM.ts(null);
scope.hs = crmUiHelp({file: 'CRM/Mailing/MailingUI'});
scope.checkPerm = CRM.checkPerm;

scope.addReplyTo = () => crmMosaicoVariants.split(scope.mailing, 'replyto_email');
scope.rmReplyTo = (vid) => crmMosaicoVariants.remove(scope.mailing, 'replyto_email', vid);
scope.isSplit = () => crmMosaicoVariants.isSplit(scope.mailing, 'replyto_email');
scope.labels = crmMosaicoVariants.getLabels();
}
};

});
})(angular, CRM.$, CRM._);
4 changes: 2 additions & 2 deletions ang/crmMosaico/SubjectList.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

<input crm-mailing-token on-select="$broadcast('insert:subject', token.name)" tabindex="-1" class="form-control"/>

<a ng-click="addSubj()" class="btn btn-default" title="{{ts('Add subject')}}">
<a ng-click="addSubj()" class="btn btn-default" title="{{ts('Add alternate \'Subject\'')}}">
<span><i class="crm-i fa-plus-circle"></i></span>
</a>

Expand All @@ -39,7 +39,7 @@

<input crm-mailing-token on-select="$broadcast('insert:subject', token.name)" tabindex="-1" class="form-control"/>

<a ng-click="rmSubj(vid)" class="btn btn-default" title="{{ts('Remove subject')}}">
<a ng-click="rmSubj(vid)" class="btn btn-default" title="{{ts('Remove alternate \'Subject\'')}}">
<span><i class="crm-i fa-trash"></i></span>
</a>

Expand Down
11 changes: 10 additions & 1 deletion ang/crmMosaico/Variants.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,16 @@
return JSON.parse(angular.toJson(obj));
}

const mainPlaceholders = {subject: 'VARIANT SUBJECTS', body_html: 'VARIANT HTMLS', mosaicoTemplate: "", mosaicoMetadata: '{}', mosaicoContent: '{}'};
const mainPlaceholders = {
subject: 'VARIANT SUBJECTS',
body_html: 'VARIANT HTMLS',
from_name: 'VARIANT FROM',
from_email: 'VARIANT@EXAMPLE.ORG',
replyto_email: '"VARIANT FROM" <VARIANT@EXAMPLE.ORG>',
mosaicoTemplate: "",
mosaicoMetadata: '{}',
mosaicoContent: '{}'
};

const self = {
getLabels: () => ['A', 'B'],
Expand Down
6 changes: 6 additions & 0 deletions tests/phpunit/CRM/Mosaico/AbDemuxTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ public function getVariantExamples(): array {
['subject' => 'New Subject A', 'body_html' => 'New Html A'],
['subject' => 'New Subject B', 'body_html' => 'New Html B'],
];
$cases[] = [
['from_email' => 'albert@example.org', 'from_name' => 'Albert Albertson', 'subject' => 'Subject A'],
['from_email' => 'albert@example.org', 'from_name' => 'Barb Barbagelata', 'subject' => 'Subject B'],
['from_email' => 'albert@example.org', 'from_name' => 'Albert Albertson', 'subject' => 'Subject A'],
['from_email' => 'albert@example.org', 'from_name' => 'Barb Barbagelata', 'subject' => 'Subject B'],
];

return $cases;
}
Expand Down
Loading