From f2e83bf57ff4ede12ae6690fb4036f4b589f2809 Mon Sep 17 00:00:00 2001 From: Renzo Lucioni Date: Tue, 16 Dec 2014 17:28:30 -0500 Subject: [PATCH] Split payment/verification business intelligence analytics Track verify now and verify later choices, image captures, image retake, and name changes, as well as virtual pageviews for every step in the new flow(s). --- .../models/verification_model.js | 15 +++++++++----- .../views/face_photo_step_view.js | 13 +++++++++--- .../views/id_photo_step_view.js | 15 ++++++++++---- .../views/make_payment_step_view.js | 5 +++++ .../views/payment_confirmation_step_view.js | 20 ++++++++++++++++--- .../views/review_photos_step_view.js | 19 +++++++++++------- .../js/verify_student/views/step_view.js | 3 +++ .../verify_student/views/webcam_photo_view.js | 4 ++++ .../review_photos_step.underscore | 2 +- lms/templates/widgets/segment-io.html | 3 ++- 10 files changed, 75 insertions(+), 24 deletions(-) diff --git a/lms/static/js/verify_student/models/verification_model.js b/lms/static/js/verify_student/models/verification_model.js index ab542afec2..e9dc0a16a1 100644 --- a/lms/static/js/verify_student/models/verification_model.js +++ b/lms/static/js/verify_student/models/verification_model.js @@ -22,16 +22,21 @@ }, sync: function( method, model ) { - var headers = { 'X-CSRFToken': $.cookie('csrftoken') }, + var headers = { 'X-CSRFToken': $.cookie( 'csrftoken' ) }, data = { - face_image: model.get('faceImage'), - photo_id_image: model.get('identificationImage') + face_image: model.get( 'faceImage' ), + photo_id_image: model.get( 'identificationImage' ) }; // Full name is an optional parameter; if not provided, // it won't be changed. - if ( !_.isNull( model.get('fullName') ) ) { - data.full_name = model.get('fullName'); + if ( !_.isEmpty( model.get( 'fullName' ) ) ) { + data.full_name = model.get( 'fullName' ); + + // Track the user's decision to change the name on their account + window.analytics.track( 'edx.bi.user.full_name.changed', { + category: 'verification' + }); } // Submit the request to the server, diff --git a/lms/static/js/verify_student/views/face_photo_step_view.js b/lms/static/js/verify_student/views/face_photo_step_view.js index 163387cf18..17822b688a 100644 --- a/lms/static/js/verify_student/views/face_photo_step_view.js +++ b/lms/static/js/verify_student/views/face_photo_step_view.js @@ -11,15 +11,22 @@ var edx = edx || {}; edx.verify_student.FacePhotoStepView = edx.verify_student.StepView.extend({ postRender: function() { - new edx.verify_student.WebcamPhotoView({ - el: $("#facecam"), + var webcam = new edx.verify_student.WebcamPhotoView({ + el: $( '#facecam' ), model: this.model, modelAttribute: 'faceImage', submitButton: '#next_step_button', errorModel: this.errorModel }).render(); - $('#next_step_button').on( 'click', _.bind( this.nextStep, this ) ); + this.listenTo( webcam, 'imageCaptured', function() { + // Track the user's successful image capture + window.analytics.track( 'edx.bi.user.face_image.captured', { + category: 'verification' + }); + }); + + $( '#next_step_button' ).on( 'click', _.bind( this.nextStep, this ) ); }, }); diff --git a/lms/static/js/verify_student/views/id_photo_step_view.js b/lms/static/js/verify_student/views/id_photo_step_view.js index 77ec5cc6e2..cb7724f444 100644 --- a/lms/static/js/verify_student/views/id_photo_step_view.js +++ b/lms/static/js/verify_student/views/id_photo_step_view.js @@ -11,16 +11,23 @@ var edx = edx || {}; edx.verify_student.IDPhotoStepView = edx.verify_student.StepView.extend({ postRender: function() { - new edx.verify_student.WebcamPhotoView({ - el: $("#idcam"), + var webcam = new edx.verify_student.WebcamPhotoView({ + el: $( '#idcam' ), model: this.model, modelAttribute: 'identificationImage', submitButton: '#next_step_button', errorModel: this.errorModel }).render(); - $('#next_step_button').on( 'click', _.bind( this.nextStep, this ) ); - }, + this.listenTo( webcam, 'imageCaptured', function() { + // Track the user's successful image capture + window.analytics.track( 'edx.bi.user.identification_image.captured', { + category: 'verification' + }); + }); + + $( '#next_step_button' ).on( 'click', _.bind( this.nextStep, this ) ); + } }); })( jQuery ); diff --git a/lms/static/js/verify_student/views/make_payment_step_view.js b/lms/static/js/verify_student/views/make_payment_step_view.js index 138e55d198..d5b59fd726 100644 --- a/lms/static/js/verify_student/views/make_payment_step_view.js +++ b/lms/static/js/verify_student/views/make_payment_step_view.js @@ -75,6 +75,11 @@ var edx = edx || {}; }).appendTo(form); }); + // Marketing needs a way to tell the difference between users + // leaving for the payment processor and users dropping off on + // this page. A virtual pageview can be used to do this. + window.analytics.page( 'verification', 'payment_processor_step' ); + form.submit(); }, diff --git a/lms/static/js/verify_student/views/payment_confirmation_step_view.js b/lms/static/js/verify_student/views/payment_confirmation_step_view.js index ec77fb2527..40e0129241 100644 --- a/lms/static/js/verify_student/views/payment_confirmation_step_view.js +++ b/lms/static/js/verify_student/views/payment_confirmation_step_view.js @@ -9,7 +9,6 @@ var edx = edx || {}; edx.verify_student = edx.verify_student || {}; edx.verify_student.PaymentConfirmationStepView = edx.verify_student.StepView.extend({ - /** * Retrieve receipt information from the shopping cart. * @@ -68,9 +67,24 @@ var edx = edx || {}; * The "Verify Now" button reloads this page with the "skip-first-step" * flag set. This allows the user to navigate back to the confirmation * if he/she wants to. - * For this reason, we don't need any custom click handlers here. + * For this reason, we don't need any custom click handlers here, except for + * those used to track business intelligence events. */ - postRender: function() {}, + postRender: function() { + // Track the user's decision to verify immediately + $( '#verify_now_button' ).on( 'click', function() { + window.analytics.track( 'edx.bi.user.verification.immediate', { + category: 'verification' + }); + }); + + // Track the user's decision to defer their verification + $( '#verify_later_button' ).on( 'click', function() { + window.analytics.track( 'edx.bi.user.verification.deferred', { + category: 'verification' + }); + }); + }, /** * Retrieve receipt data from the shoppingcart. diff --git a/lms/static/js/verify_student/views/review_photos_step_view.js b/lms/static/js/verify_student/views/review_photos_step_view.js index ebd9d575dd..8617893b09 100644 --- a/lms/static/js/verify_student/views/review_photos_step_view.js +++ b/lms/static/js/verify_student/views/review_photos_step_view.js @@ -14,8 +14,8 @@ var edx = edx || {}; var model = this.model; // Load the photos from the previous steps - $( "#face_image")[0].src = this.model.get('faceImage'); - $( "#photo_id_image")[0].src = this.model.get('identificationImage'); + $( '#face_image' )[0].src = this.model.get('faceImage'); + $( '#photo_id_image' )[0].src = this.model.get('identificationImage'); // Prep the name change dropdown $( '.expandable-area' ).slideUp(); @@ -37,12 +37,17 @@ var edx = edx || {}; }, retakePhotos: function() { + // Track the user's intent to retake their photos + window.analytics.track( 'edx.bi.user.verification_images.retaken', { + category: 'verification' + }); + this.goToStep( 'face-photo-step' ); }, submitPhotos: function() { // Disable the submit button to prevent duplicate submissions - $( "#next_step_button" ).addClass( "is-disabled" ); + $( '#next_step_button' ).addClass( 'is-disabled' ); // On success, move on to the next step this.listenToOnce( this.model, 'sync', _.bind( this.nextStep, this ) ); @@ -57,8 +62,8 @@ var edx = edx || {}; handleSubmissionError: function( xhr ) { // Re-enable the submit button to allow the user to retry - var isConfirmChecked = $( "#confirm_pics_good" ).prop('checked'); - $( "#next_step_button" ).toggleClass( "is-disabled", !isConfirmChecked ); + var isConfirmChecked = $( '#confirm_pics_good' ).prop( 'checked' ); + $( '#next_step_button' ).toggleClass( 'is-disabled', !isConfirmChecked ); // Display the error if ( xhr.status === 400 ) { @@ -77,14 +82,14 @@ var edx = edx || {}; } }, - expandCallback: function(event) { + expandCallback: function( event ) { event.preventDefault(); $(this).next('.expandable-area' ).slideToggle(); var title = $( this ).parent(); title.toggleClass( 'is-expanded' ); - title.attr( 'aria-expanded', !title.attr('aria-expanded') ); + title.attr( 'aria-expanded', !title.attr( 'aria-expanded' ) ); } }); diff --git a/lms/static/js/verify_student/views/step_view.js b/lms/static/js/verify_student/views/step_view.js index 869754566a..a069b96eb9 100644 --- a/lms/static/js/verify_student/views/step_view.js +++ b/lms/static/js/verify_student/views/step_view.js @@ -47,6 +47,9 @@ this.postRender(); } ).fail( _.bind( this.handleError, this ) ); + + // Track a virtual pageview, for easy funnel reconstruction. + window.analytics.page( 'verification', this.templateName ); }, handleResponse: function( data ) { diff --git a/lms/static/js/verify_student/views/webcam_photo_view.js b/lms/static/js/verify_student/views/webcam_photo_view.js index c527da61a7..d1f00f8495 100644 --- a/lms/static/js/verify_student/views/webcam_photo_view.js +++ b/lms/static/js/verify_student/views/webcam_photo_view.js @@ -262,6 +262,10 @@ var success = this.backend.snapshot(); if ( success ) { + // Trigger an event which parent views can use to fire a + // business intelligence event + this.trigger( 'imageCaptured' ); + // Hide the capture button, and show the reset button $( "#webcam_capture_button", this.el ).hide(); $( "#webcam_reset_button", this.el ).show(); diff --git a/lms/templates/verify_student/review_photos_step.underscore b/lms/templates/verify_student/review_photos_step.underscore index c19c9b9208..8e6770353f 100644 --- a/lms/templates/verify_student/review_photos_step.underscore +++ b/lms/templates/verify_student/review_photos_step.underscore @@ -78,7 +78,7 @@

<%- gettext( "You should change the name on your account to match." ) %>

- > + >
diff --git a/lms/templates/widgets/segment-io.html b/lms/templates/widgets/segment-io.html index 77953ce40d..6c6c791a90 100644 --- a/lms/templates/widgets/segment-io.html +++ b/lms/templates/widgets/segment-io.html @@ -19,7 +19,8 @@