$scope.sync();
return crmStatus({start: ts('Saving...'), success: ''}, abtest.save())
.then(function () {
- return crmStatus({start: ts('Submitting...'), success: ts('Submitted')}, abtest.submit('Testing'));
+ return crmStatus({start: ts('Submitting...'), success: ts('Submitted')}, abtest.submitTest());
// Note: We're going to leave, so we don't care that submit() modifies several server-side records.
- // If we stayed on this page, then we'd care about updating and call: abtest.submit().then(abtest.load)
+ // If we stayed on this page, then we'd care about updating and call: abtest.submitTest().then(...abtest.load()...)
})
.then(leave);
};
$scope.$watch('abtest.ab.testing_criteria_id', updateCriteriaName);
});
- angular.module('crmMailingAB').controller('CrmMailingABReportCtrl', function ($scope, abtest, crmMailingABCriteria, crmApi) {
+ angular.module('crmMailingAB').controller('CrmMailingABReportCtrl', function ($scope, abtest, crmApi, crmMailingPreviewMgr, dialogService) {
var ts = $scope.ts = CRM.ts('CiviMail');
$scope.abtest = abtest;
crmApi('Mailing', 'stats', {mailing_id: abtest.ab.mailing_id_b}).then(function(data){
$scope.stats.b = data.values[abtest.ab.mailing_id_b];
});
+ crmApi('Mailing', 'stats', {mailing_id: abtest.ab.mailing_id_c}).then(function(data){
+ $scope.stats.c = data.values[abtest.ab.mailing_id_c];
+ });
+
+ $scope.previewMailing = function previewMailing(mailingName, mode) {
+ return crmMailingPreviewMgr.preview(abtest.mailings[mailingName], mode);
+ };
+ $scope.selectWinner = function selectWinner(mailingName) {
+ var model = {
+ abtest: abtest,
+ mailingName: mailingName
+ };
+ var options = {
+ autoOpen: false,
+ modal: true,
+ title: ts('Select Winner (%1)', {
+ 1: mailingName.toUpperCase()
+ })
+ };
+ return dialogService.open('selectWinnerDialog', partialUrl('selectWinner.html'), model, options);
+ };
+ });
+
+
+ angular.module('crmMailingAB').controller('CrmMailingABWinnerDialogCtrl', function ($scope, $timeout, dialogService, crmMailingMgr, crmStatus) {
+ var ts = $scope.ts = CRM.ts('CiviMail');
+ var abtest = $scope.abtest = $scope.model.abtest;
+ var mailingName = $scope.model.mailingName;
+
+ var titles = {a: ts('Mailing A'), b: ts('Mailing B')};
+ $scope.mailingTitle = titles[mailingName];
+
+ function init() {
+ // When using dialogService with a button bar, the major button actions
+ // need to be registered with the dialog widget (and not embedded in
+ // the body of the dialog).
+ var buttons = {};
+ buttons[ts('Select Winner')] = function () {
+ crmMailingMgr.mergeInto(abtest.mailings.c, abtest.mailings[mailingName], [
+ 'name',
+ 'groups',
+ 'mailings',
+ 'scheduled_date'
+ ]);
+ crmStatus({start: ts('Saving...'), success: ''}, abtest.save())
+ .then(function () {
+ return crmStatus({start: ts('Submitting...'), success: ts('Submitted')},
+ abtest.submitFinal().then(function(){
+ return abtest.load();
+ }));
+ })
+ .then(function(){
+ dialogService.close('selectWinnerDialog', abtest);
+ });
+ };
+ buttons[ts('Cancel')] = function () {
+ dialogService.cancel('selectWinnerDialog');
+ };
+ dialogService.setButtons('selectWinnerDialog', buttons);
+ }
+
+ $timeout(init);
});
})(angular, CRM.$, CRM._);
.then(function () {
return crmApi('MailingAB', 'create', crmMailingAB.ab)
.then(function (abResult) {
- crmMailingAB.ab.id = abResult.id;
+ crmMailingAB.id = crmMailingAB.ab.id = abResult.id;
});
})
.then(function () {
},
// Schedule the test
// @return Promise CrmMailingAB
- // Note: Submission may cause the server state to change. Consider abtest.submit().then(abtest.load)
- submit: function submit(newStatus) {
+ // Note: Submission may cause the server state to change. Consider abtest.submit().then(...abtest.load()...)
+ submitTest: function submitTest() {
var crmMailingAB = this;
var params = {
id: this.ab.id,
- status: newStatus,
+ status: 'Testing',
approval_date: crmNow(),
scheduled_date: this.mailings.a.scheduled_date ? this.mailings.a.scheduled_date : crmNow()
};
return crmMailingAB;
});
},
+ // Schedule the final mailing
+ // @return Promise CrmMailingAB
+ // Note: Submission may cause the server state to change. Consider abtest.submit().then(...abtest.load()...)
+ submitFinal: function submitFinal() {
+ var crmMailingAB = this;
+ var params = {
+ id: this.ab.id,
+ status: 'Final',
+ approval_date: crmNow(),
+ scheduled_date: this.mailings.c.scheduled_date ? this.mailings.c.scheduled_date : crmNow()
+ };
+ return crmApi('MailingAB', 'submit', params)
+ .then(function () {
+ return crmMailingAB;
+ });
+ },
// @param mailing Object (per APIv3)
// @return Promise
'delete': function () {
-<div>
+<div crm-ui-accordion crm-title="ts('Debug')" crm-collapsed="true">
+ <pre>{{abtest.ab|json}}</pre>
+ <pre>{{abtest.mailings|json}}</pre>
+</div>
+<div>
<table>
<thead>
<tr>
<th>{{ts('Details')}}</th>
- <th style="width: 10em;">{{ts('Mailing A')}}</th>
- <th style="width: 10em;">{{ts('Mailing B')}}</th>
+ <th style="width: 12em;">{{ts('Mailing A')}}</th>
+ <th style="width: 12em;">{{ts('Mailing B')}}</th>
+ <th style="width: 12em;" ng-show="abtest.ab.status == 'Final'">{{ts('Final')}}</th>
</tr>
</thead>
<tbody>
+ <tr ng-show="abtest.mailings.a.body_html || abtest.mailings.b.body_html">
+ <td>{{ts('HTML')}}</td>
+ <td><a ng-click="previewMailing('a','html')" ng-show="abtest.mailings.a.body_html">{{ts('View')}}</a></td>
+ <td><a ng-click="previewMailing('b','html')" ng-show="abtest.mailings.b.body_html">{{ts('View')}}</a></td>
+ <td><a ng-click="previewMailing('c','html')" ng-show="abtest.mailings.c.body_html && abtest.ab.status == 'Final'">{{ts('View')}}</a></td>
+ </tr>
+ <tr ng-show="abtest.mailings.a.body_text || abtest.mailings.b.body_text">
+ <td>{{ts('Text')}}</td>
+ <td><a ng-click="previewMailing('a','text')" ng-show="abtest.mailings.a.body_text">{{ts('View')}}</a></td>
+ <td><a ng-click="previewMailing('b','text')" ng-show="abtest.mailings.b.body_text">{{ts('View')}}</a></td>
+ <td><a ng-click="previewMailing('c','text')" ng-show="abtest.mailings.c.body_text && abtest.ab.status == 'Final'">{{ts('View')}}</a></td>
+ </tr>
<tr>
<td>{{ts('Delivered')}}</td>
<td>{{stats.a.Delivered}}</td>
<td>{{stats.b.Delivered}}</td>
+ <td ng-show="abtest.ab.status == 'Final'">{{stats.c.Delivered}}</td>
</tr>
<tr>
<td>{{ts('Bounces')}}</td>
<td>{{stats.a.Bounces}}</td>
<td>{{stats.b.Bounces}}</td>
+ <td ng-show="abtest.ab.status == 'Final'">{{stats.c.Bounces}}</td>
</tr>
<tr>
<td>{{ts('Unsubscribers')}}</td>
<td>{{stats.a.Unsubscribers}}</td>
<td>{{stats.b.Unsubscribers}}</td>
+ <td ng-show="abtest.ab.status == 'Final'">{{stats.c.Unsubscribers}}</td>
</tr>
<tr>
<td>{{'Opened'}}</td>
<td>{{stats.a.Opened}}</td>
<td>{{stats.b.Opened}}</td>
+ <td ng-show="abtest.ab.status == 'Final'">{{stats.c.Opened}}</td>
</tr>
<tr>
<td>{{ts('Unique Clicks')}}</td>
<td>{{stats.a['Unique Clicks']}}</td>
<td>{{stats.b['Unique Clicks']}}</td>
+ <td ng-show="abtest.ab.status == 'Final'">{{stats.c['Unique Clicks']}}</td>
+ </tr>
+ <tr ng-show="abtest.ab.status == 'Testing'">
+ <td></td>
+ <td>
+ <button ng-click="selectWinner('a')">{{ts('Select as Winner')}}</button>
+ </td>
+ <td>
+ <button ng-click="selectWinner('b')">{{ts('Select as Winner')}}</button>
+ </td>
+ <!-- Final column is n/a -->
</tr>
</tbody>
</table>
--- /dev/null
+<div ng-controller="CrmMailingABWinnerDialogCtrl">
+ <form novalidate name="winnerForm">
+ <div id="help">
+ {{ts('After selecting %1 as the winner, one must schedule the delivery for the final mailing.', {1: mailingTitle})}}
+ </div>
+
+ <div crm-mailing-radio-date="schedule" crm-model="abtest.mailings.c.scheduled_date">
+ <div>
+ <input ng-model="schedule.mode" type="radio" name="send" value="now" id="schedule-send-now"/>
+ <label for="schedule-send-now">{{ts('Send final mailing immediately')}}</label>
+ </div>
+ <div>
+ <input ng-model="schedule.mode" type="radio" name="send" value="at" id="schedule-send-at"/>
+ <label for="schedule-send-at">{{ts('Send final mailing at:')}}</label>
+ <span crm-ui-date-time="schedule.datetime"></span>
+ </div>
+ </div>
+ </form>
+</div>