CRM-15979 - crmMailingAB - Merge the compose and report URLs
[civicrm-core.git] / js / angular-crmMailingAB.js
1 (function (angular, $, _) {
2
3 angular.module('crmMailingAB', ['ngRoute', 'ui.utils', 'ngSanitize', 'crmUi', 'crmAttachment', 'crmMailing', 'crmD3']);
4 angular.module('crmMailingAB').config([
5 '$routeProvider',
6 function ($routeProvider) {
7 $routeProvider.when('/abtest', {
8 templateUrl: '~/crmMailingAB/list.html',
9 controller: 'CrmMailingABListCtrl',
10 resolve: {
11 mailingABList: function ($route, crmApi) {
12 return crmApi('MailingAB', 'get', {rowCount: 0});
13 },
14 fields: function(crmMetadata){
15 return crmMetadata.getFields('MailingAB');
16 }
17 }
18 });
19 $routeProvider.when('/abtest/new', {
20 template: '<p>' + ts('Initializing...') + '</p>',
21 controller: 'CrmMailingABNewCtrl',
22 resolve: {
23 abtest: function ($route, CrmMailingAB) {
24 var abtest = new CrmMailingAB(null);
25 return abtest.load().then(function(){
26 return abtest.save();
27 });
28 }
29 }
30 });
31 $routeProvider.when('/abtest/:id', {
32 templateUrl: '~/crmMailingAB/edit.html',
33 controller: 'CrmMailingABEditCtrl',
34 resolve: {
35 abtest: function ($route, CrmMailingAB) {
36 var abtest = new CrmMailingAB($route.current.params.id == 'new' ? null : $route.current.params.id);
37 return abtest.load();
38 }
39 }
40 });
41 $routeProvider.when('/abtest/:id/report', {
42 templateUrl: '~/crmMailingAB/report.html',
43 controller: 'CrmMailingABReportCtrl',
44 resolve: {
45 abtest: function ($route, CrmMailingAB) {
46 var abtest = new CrmMailingAB($route.current.params.id);
47 return abtest.load();
48 }
49 }
50 });
51 }
52 ]);
53
54 angular.module('crmMailingAB').controller('CrmMailingABListCtrl', function($scope, mailingABList, crmMailingABCriteria, crmMailingABStatus, fields) {
55 var ts = $scope.ts = CRM.ts(null);
56 $scope.mailingABList = _.values(mailingABList.values);
57 $scope.crmMailingABCriteria = crmMailingABCriteria;
58 $scope.crmMailingABStatus = crmMailingABStatus;
59 $scope.fields = fields;
60 $scope.filter = {};
61 });
62
63 angular.module('crmMailingAB').controller('CrmMailingABNewCtrl', function ($scope, abtest, $location) {
64 // Transition URL "/abtest/new/foo" => "/abtest/123/foo"
65 var parts = $location.path().split('/'); // e.g. "/mailing/new" or "/mailing/123/wizard"
66 parts[2] = abtest.id;
67 $location.path(parts.join('/'));
68 $location.replace();
69 });
70
71 angular.module('crmMailingAB').controller('CrmMailingABEditCtrl', function ($scope, abtest, crmMailingABCriteria, crmMailingMgr, crmMailingPreviewMgr, crmStatus, $q, $location, crmBlocker, $interval) {
72 $scope.abtest = abtest;
73 var ts = $scope.ts = CRM.ts(null);
74 var block = $scope.block = crmBlocker();
75 $scope.crmMailingABCriteria = crmMailingABCriteria;
76 $scope.crmMailingConst = CRM.crmMailing;
77
78 $scope.isSubmitted = function isSubmitted() {
79 return _.size(abtest.mailings.a.jobs) > 0 || _.size(abtest.mailings.b.jobs) > 0;
80 };
81
82 $scope.sync = function sync() {
83 abtest.mailings.a.name = ts('Test A (%1)', {1: abtest.ab.name});
84 abtest.mailings.b.name = ts('Test B (%1)', {1: abtest.ab.name});
85 abtest.mailings.c.name = ts('Winner (%1)', {1: abtest.ab.name});
86
87 if (abtest.ab.testing_criteria) {
88 // TODO review fields exposed in UI and make sure the sync rules match
89 switch (abtest.ab.testing_criteria) {
90 case 'subject':
91 crmMailingMgr.mergeInto(abtest.mailings.b, abtest.mailings.a, [
92 'name',
93 'recipients',
94 'subject'
95 ]);
96 break;
97 case 'from':
98 crmMailingMgr.mergeInto(abtest.mailings.b, abtest.mailings.a, [
99 'name',
100 'recipients',
101 'from_name',
102 'from_email'
103 ]);
104 break;
105 case 'full_email':
106 crmMailingMgr.mergeInto(abtest.mailings.b, abtest.mailings.a, [
107 'name',
108 'recipients',
109 'subject',
110 'from_name',
111 'from_email',
112 'replyto_email',
113 'override_verp', // keep override_verp and replyto_Email linked
114 'body_html',
115 'body_text'
116 ]);
117 break;
118 default:
119 throw "Unrecognized testing_criteria";
120 }
121 }
122 crmMailingMgr.mergeInto(abtest.mailings.c, abtest.mailings.a, ['name']);
123 return true;
124 };
125
126 // @return Promise
127 $scope.save = function save() {
128 return block(crmStatus({start: ts('Saving...'), success: ts('Saved')}, abtest.save()));
129 };
130
131 // @return Promise
132 $scope.previewMailing = function previewMailing(mailingName, mode) {
133 return crmMailingPreviewMgr.preview(abtest.mailings[mailingName], mode);
134 };
135
136 // @return Promise
137 $scope.sendTest = function sendTest(mailingName, recipient) {
138 return block(crmStatus({start: ts('Saving...'), success: ''}, abtest.save())
139 .then(function () {
140 crmMailingPreviewMgr.sendTest(abtest.mailings[mailingName], recipient);
141 }));
142 };
143
144 // @return Promise
145 $scope.delete = function () {
146 return block(crmStatus({start: ts('Deleting...'), success: ts('Deleted')}, abtest.delete().then($scope.leave)));
147 };
148
149 // @return Promise
150 $scope.submit = function submit() {
151 if (block.check() || $scope.crmMailingAB.$invalid) {
152 return;
153 }
154 return block(crmStatus({start: ts('Saving...'), success: ''}, abtest.save())
155 .then(function() {
156 return crmStatus({start: ts('Submitting...'), success: ts('Submitted')}, abtest.submitTest());
157 // Note: We're going to leave, so we don't care that submit() modifies several server-side records.
158 // If we stayed on this page, then we'd care about updating and call: abtest.submitTest().then(...abtest.load()...)
159 })
160 ).then($scope.leave);
161 };
162
163 $scope.leave = function leave() {
164 $location.path('abtest');
165 $location.replace();
166 };
167
168 // initialize
169 var syncJob = $interval($scope.sync, 333);
170 $scope.$on('$destroy', function(){
171 $interval.cancel(syncJob);
172 });
173 });
174
175 angular.module('crmMailingAB').controller('CrmMailingABReportCtrl', function ($scope, crmApi, crmMailingPreviewMgr, dialogService) {
176 var ts = $scope.ts = CRM.ts(null);
177
178 $scope.stats = {};
179 crmApi('Mailing', 'stats', {mailing_id: $scope.abtest.ab.mailing_id_a}).then(function(data){
180 $scope.stats.a = data.values[$scope.abtest.ab.mailing_id_a];
181 });
182 crmApi('Mailing', 'stats', {mailing_id: $scope.abtest.ab.mailing_id_b}).then(function(data){
183 $scope.stats.b = data.values[$scope.abtest.ab.mailing_id_b];
184 });
185 crmApi('Mailing', 'stats', {mailing_id: $scope.abtest.ab.mailing_id_c}).then(function(data){
186 $scope.stats.c = data.values[$scope.abtest.ab.mailing_id_c];
187 });
188
189 $scope.previewMailing = function previewMailing(mailingName, mode) {
190 return crmMailingPreviewMgr.preview(abtest.mailings[mailingName], mode);
191 };
192 $scope.selectWinner = function selectWinner(mailingName) {
193 var model = {
194 abtest: $scope.abtest,
195 mailingName: mailingName
196 };
197 var options = CRM.utils.adjustDialogDefaults({
198 autoOpen: false,
199 title: ts('Select Winner (%1)', {
200 1: mailingName.toUpperCase()
201 })
202 });
203 return dialogService.open('selectWinnerDialog', '~/crmMailingAB/selectWinner.html', model, options);
204 };
205 });
206
207
208 angular.module('crmMailingAB').controller('CrmMailingABWinnerDialogCtrl', function ($scope, $timeout, dialogService, crmMailingMgr, crmStatus) {
209 var ts = $scope.ts = CRM.ts(null);
210 var abtest = $scope.abtest = $scope.model.abtest;
211 var mailingName = $scope.model.mailingName;
212
213 var titles = {a: ts('Mailing A'), b: ts('Mailing B')};
214 $scope.mailingTitle = titles[mailingName];
215
216 function init() {
217 // When using dialogService with a button bar, the major button actions
218 // need to be registered with the dialog widget (and not embedded in
219 // the body of the dialog).
220 var buttons = {};
221 buttons[ts('Select Winner')] = function () {
222 crmMailingMgr.mergeInto(abtest.mailings.c, abtest.mailings[mailingName], [
223 'name',
224 'recipients',
225 'scheduled_date'
226 ]);
227 crmStatus({start: ts('Saving...'), success: ''}, abtest.save())
228 .then(function () {
229 return crmStatus({start: ts('Submitting...'), success: ts('Submitted')},
230 abtest.submitFinal().then(function(){
231 return abtest.load();
232 }));
233 })
234 .then(function(){
235 dialogService.close('selectWinnerDialog', abtest);
236 });
237 };
238 buttons[ts('Cancel')] = function () {
239 dialogService.cancel('selectWinnerDialog');
240 };
241 dialogService.setButtons('selectWinnerDialog', buttons);
242 }
243
244 $timeout(init);
245 });
246
247 })(angular, CRM.$, CRM._);